为什么std :: function不能绑定到C风格的可变参数函数?

时间:2013-08-22 01:47:51

标签: c++ c++11

例如,这无法编译:

std::function<decltype(printf)> my_printf(printf);

使用gcc,错误消息显示为:

error: variable 'std::function<int(const char*, ...)> my_printf' has initializer but incomplete type
     std::function<decltype(printf)> my_printf(printf);

起初我认为这是gcc中的一个错误,但后来我看了标准,看起来这样就不支持了。这是什么技术原因?

2 个答案:

答案 0 :(得分:7)

问题是实施问题。让我们说这是可能的。然后std::function必须声明(在printf的情况下)

int operator()(char* fmt, ...)

当被调用时,它必须将...的内容传递给您指定的任何对象。问题在于它不知道如何知道如何将其传递下来,这是一个问题。 printf()解析格式,但其他人使用其他机制('end'值很受欢迎)。

对于printf系列函数,我建议您查看vXXX版本(例如vprintf)。由于它们使用定义良好的参数(最后一个是变量参数列表),因此可以将std::function绑定到这些版本。

编辑:

然而,你可以做的是编写自己的使用vprintf函数的包装器,并处理vararg-&gt; va_list转换。

#include <cstdio>
#include <cstdarg>
#include <functional>

class PrintWrapper
{

    public:
    PrintWrapper()  = default;


    template<typename T>
    PrintWrapper( T&& t)  : func(std::forward<T>(t))
    {

    }


    int operator()(char const* format, ...)
    {
        va_list args;
        va_start(args, format);
        int result = func(format, args);
        va_end(args);
        return result;
    }
    private:

    std::function< int(char const*, va_list)> func;

};

int main()
{
    // Note, you have to use the 'v' versions
    PrintWrapper p = std::vprintf;
    p("%d %d %s\n", 1,2, "hello");
    char buffer[256];
    using namespace std::placeholders;
    p = std::bind(std::vsnprintf, buffer, sizeof(buffer), _1, _2 );

    p("%lf %s\n", 0.1234, "goodbye");

    // Since the previous step was a wrapper around snprintf, we need to print
    // the buffer it wrote into
    printf("%s\n", buffer);

    return 0;
}

http://ideone.com/Sc95ch

答案 1 :(得分:0)

编写自己的模板类。

template<typename F>
struct function2
{
    F f;

    template<typename... Args>
    decltype(auto) operator()(Args&&... a)
    {
        return f(a...);
    }
};


function2 a{ printf };
a("%d %u %x %p %s", 1, 1, 1, &a, "test");