C++ std::function可以用于存储具有可变参数的函数吗
我有一个在应用程序中传递的结构,其中包含一系列回调函数:C++ std::function可以用于存储具有可变参数的函数吗,c++,function-pointers,variadic-functions,std-function,C++,Function Pointers,Variadic Functions,Std Function,我有一个在应用程序中传递的结构,其中包含一系列回调函数: typedef struct { std::function<void (void)> f1; std::function<void (int)> f2; std::function<int (float *)> f3; // ... and so on } CallbackTable; …并根据系统状态将输出定向到控制台、文件或GUI窗口。编辑:原始答
typedef struct {
std::function<void (void)> f1;
std::function<void (int)> f2;
std::function<int (float *)> f3;
// ... and so on
} CallbackTable;
…并根据系统状态将输出定向到控制台、文件或GUI窗口。编辑:原始答案错误,已修改,但可能仍然不是一个好答案,将其保留在此处用于教育目的: 许多变量参数函数都有va_列表版本<例如,code>printf具有
vprintf
。这些变体显式地采用va_列表,而不是椭圆
#include <iostream>
#include <functional>
#include <cstdarg>
int main()
{
std::function<int(const char*,va_list)> test2(vprintf);
return 0;
}
#包括
#包括
#包括
int main()
{
std::功能测试2(vprintf);
返回0;
}
然而,调用它是一种痛苦
int invoke_variadic(const std::function<int(const char*,va_list)>& ref,const char* a ,...)
{
va_list args;
va_start(args,a);
ref(a,args);
va_end(args);
}
int invoke_variadic(常量std::function&ref,常量char*a,…)
{
va_列表参数;
va_启动(args,a);
参考(a,args);
va_端(args);
}
原来的帖子有什么问题(谢谢/u/T.C.):
std::function test2(printf)
compiles,我认为这意味着它“有效”。但是它可以编译,因为printf可以接受任何类型的参数(包括va_列表),并且std::function
仅检查是否可以以这种方式调用它。编辑:原始答案是错误的,经过修改,但可能仍然不是一个好答案,将其保留在此处用于教育目的:
许多变量参数函数都有va_列表版本<例如,code>printf具有vprintf
。这些变体显式地采用va_列表,而不是椭圆
#include <iostream>
#include <functional>
#include <cstdarg>
int main()
{
std::function<int(const char*,va_list)> test2(vprintf);
return 0;
}
#包括
#包括
#包括
int main()
{
std::功能测试2(vprintf);
返回0;
}
然而,调用它是一种痛苦
int invoke_variadic(const std::function<int(const char*,va_list)>& ref,const char* a ,...)
{
va_list args;
va_start(args,a);
ref(a,args);
va_end(args);
}
int invoke_variadic(常量std::function&ref,常量char*a,…)
{
va_列表参数;
va_启动(args,a);
参考(a,args);
va_端(args);
}
原来的帖子有什么问题(谢谢/u/T.C.):
std::function test2(printf)
compiles,我认为这意味着它“有效”。但是它可以编译,因为printf可以接受任何类型的参数(包括一个va_列表),并且std::function
只检查它是否可以以那种方式调用。根据@MadScienceDreams的建议,这对我来说相当有效
首先,我定义了StRt::Frand对象中的变量参数版本,然后使用了这是C++ +非C来添加一些方法:
typedef struct {
std::function<void (void)> f1;
std::function<void (int)> f2;
std::function<int (float *)> f3;
// ... and so on
std::function<int (const char * format, va_list args)> vprintToStdOut;
std::function<int (const char * format, va_list args)> vprintToStdErr;
int printToStdOut(const char * format, ...)
{
va_list ap;
va_start(ap, format);
int count = vprintToStdOut(format, ap);
va_end(ap);
return count;
}
int printToStdErr(const char * format, ...)
{
va_list ap;
va_start(ap, format);
int count = vprintToStdErr(format, ap);
va_end(ap);
return count;
}
} CallbackTable;
…从这一点出发,我可以准确地使用我希望使用的语法:
myCallbackTable.printToStdOut("I like to eat at least %d bananas a day\r\n", nBananas);
根据@MadScienceDreams的建议,这对我来说相当有效
首先,我定义了StRt::Frand对象中的变量参数版本,然后使用了这是C++ +非C来添加一些方法:
typedef struct {
std::function<void (void)> f1;
std::function<void (int)> f2;
std::function<int (float *)> f3;
// ... and so on
std::function<int (const char * format, va_list args)> vprintToStdOut;
std::function<int (const char * format, va_list args)> vprintToStdErr;
int printToStdOut(const char * format, ...)
{
va_list ap;
va_start(ap, format);
int count = vprintToStdOut(format, ap);
va_end(ap);
return count;
}
int printToStdErr(const char * format, ...)
{
va_list ap;
va_start(ap, format);
int count = vprintToStdErr(format, ap);
va_end(ap);
return count;
}
} CallbackTable;
…从这一点出发,我可以准确地使用我希望使用的语法:
myCallbackTable.printToStdOut("I like to eat at least %d bananas a day\r\n", nBananas);
如果只是您感兴趣的输出,则应使用。
std::function
仅为形式为R(ArgTypes…
的函数类型定义,其中ArgTypes…
是类型参数包的包扩展(即(可能为空)类型列表)。因此,不允许使用C样式的变量函数。如果不允许对变量函数进行std::function
专门化,请查看可能的解决方法,不确定其是否相关。如果只是您感兴趣的输出,则应改为使用。std::function
仅为R(ArgTypes…
形式的函数类型定义,其中,ArgTypes…
是类型参数包的包扩展(即类型列表(可能为空))。因此,不允许使用C型变量函数。如果没有对变量函数的std::function
进行专门化,请查看可能的解决方法,不确定其是否相关。std::function test2(printf)代码>,甚至std::function test2(printf)代码>。它编译是因为…
可以匹配任何东西,而不是因为它在某种程度上是va_list
的同义词(它肯定不是)。@T.C.你是对的……我无法解释为什么它都编译。我仍然不确定到底发生了什么,但它实际上并不需要一个va_列表……但是printf有一个va_列表变体,所以我改变了我的答案以反映这一点。有没有解释为什么它会接受?在定义输入类型之后,它确实“起作用”……它起作用是因为您确实可以使用参数列表调用printf
,并获得隐式转换为int
(当然,假设没有错误格式字符串等引起的UB)std::function
实际上并不关心它存储的对象的类型,只关心它可以按照模板参数中指定的方式调用。@t.C.有意义。我更新了我的答案,std::functiontest2(printf)也是如此代码>,甚至std::function test2(printf)代码>。它编译是因为…
可以匹配任何东西,而不是因为它在某种程度上是va_list
的同义词(它肯定不是)。@T.C.你是对的……我无法解释为什么它都编译。我仍然不确定到底发生了什么,但它实际上并不需要一个va_列表……但是printf有一个va_列表变体,所以我改变了我的答案以反映这一点。有没有解释为什么它会接受?在定义输入类型之后,它确实“起作用”……它起作用是因为您确实可以使用参数列表调用printf
,并获得隐式转换为int
(当然,假设没有错误格式字符串等引起的UB)std::function
实际上并不关心它存储的对象的类型,只关心它可以按照模板参数中指定的方式调用。@t.C.有意义。我更新了我的答案。。。