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

Bri*_*ian 18 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);
Run Code Online (Sandbox Code Playgroud)

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

Dav*_*e S 7

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

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

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

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

编辑:

但是,您可以编写自己的使用vprintf函数的包装器,并处理vararg-> 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;
}
Run Code Online (Sandbox Code Playgroud)

http://ideone.com/Sc95ch

  • 我很想在我的'PrintWrapper`上做一个C++ 11风格的变量签名,然后让它在内部反弹到一个C风格的`...`变量列表,然后它就可以使用`va_list`了.只是隐藏那个`......`,尽可能远离最终用户...... (3认同)
  • 实际上,`std :: function`中的`operator()`不是问题 - 它可以只使用完美转发.棘手的部分是使内部类型擦除对象工作... (2认同)