Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
275 views
in Technique[技术] by (71.8m points)

c++ - Why can't std::function bind to C-style variadic functions?

For example, this fails to compile:

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

With gcc, the error message reads:

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

At first I thought this was a bug in gcc, but then I looked at the standard and it looks like this just isn't supported. What's the technical reason for this?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The issue is one of implementation. Let's say it was possible. Then std::function would have to declare (in the case of printf)

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

When called, it would then have to pass the contents of ... to whatever object you assigned. The issue is that it doesn't know enough about the arguments to know HOW to pass that down, which is an issue. printf() parses the format, but others use other mechanisms (an 'end' value is popular).

For the printf family of functions, I suggest you look at the vXXX versions (e.g. vprintf). Since they use well defined arguments (the last one being the variable argument list), it would be possible to bind std::function to those versions.

Edit:

What you can do, however, is write your own wrapper that uses the vprintf functions, and handles the vararg-> va_list conversion.

#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
", 1,2, "hello");
    char buffer[256];
    using namespace std::placeholders;
    p = std::bind(std::vsnprintf, buffer, sizeof(buffer), _1, _2 );

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

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

    return 0;
}

http://ideone.com/Sc95ch


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...