可以使用std :: function来存储具有可变参数的函数

时间:2014-09-04 17:30:11

标签: 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;

我通过将不同的函数绑定到各种回调来处理应用程序中的状态控制,具体取决于当前的系统状态;它工作正常。

我现在要做的是添加一些带有包含可变数量参数的签名的额外回调,类似于printf:例如,

    std::function<int  (const char * format, ...)> printToStdOut;

无法工作。在Visual C ++中,我收到一条错误消息:

error C2027: use of undefined type 'std::_Get_function_impl<_Fty>'

我仍然在感受这个C ++语法领域,并且非常感谢有关如何从这里开始的任何建议。我的首要目标是能够按照以下方式拨打电话:

myCallbackTable.printToStdOut("I've just eaten %d bananas\r\n", nBananas);

...并根据系统状态将输出定向到控制台,文件或GUI窗口。

2 个答案:

答案 0 :(得分:5)

编辑:原始回答是错误的,修改后但仍然可能不是一个好的答案,留待它用于教育目的:

许多变量参数函数都有va_list版本。例如printfvprintf。这些变体显式采用va_list而不是省略号。

#include <iostream>
#include <functional>
#include <cstdarg>


int main()
{
   std::function<int(const char*,va_list)> test2(vprintf);

   return 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);
}

原帖有什么问题(感谢/u/T.C。):std::function<int(const char*,va_list)> test2(printf)编译,我认为它意味着它“有效”。但是它编译是因为printf可以接受任何类型的参数(包括va_list),而std::function只检查它是否可以以这种方式调用。

答案 1 :(得分:0)

根据@MadScienceDreams的建议,这对我来说相当不错......

首先,我在struct中定义了std :: function对象的变量参数版本,然后使用了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;

对于控制台输出,变量参数函数的默认实现是(在声明'using namespace std :: placeholders;'之后,语法无法管理):

myCallbackTable.vprintToStdOut = std::bind(vfprintf, stdout, _1, _2);
myCallbackTable.vprintToStdErr = std::bind(vfprintf, stderr, _1, _2);

......从这一点来说,我可以使用我希望使用的语法:

myCallbackTable.printToStdOut("I like to eat at least %d bananas a day\r\n", nBananas);