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.有意义。我更新了我的答案。。。