简体   繁体   中英

Chained invocation of C++11 std::bind doesn't work

I have a problem when invoking nested std::bind expressions. The following code demonstrates the problem. It fails to compile with libc++, but works with boost:

#define BOOST 0

#if BOOST
    #include <boost/function.hpp>
    #include <boost/bind.hpp>
    using boost::function;
    using boost::bind;
#else
    #include <functional>
    using std::function;
    using std::bind;
    using std::placeholders::_1;
#endif


int sum(int a, int b) { return a+b; }

// works
template <typename F>
int yeah(F f, int c)
{
    return f(c);
}

// breaks with libc++
template <typename F>
int nope(F f, int c)
{
    return bind(f, c)();
}

// fixes the problem
template <typename F>
int fix1(F f, int c)
{
    function<int(int)> g = f;
    return bind(g, c)();
}

template <typename F>
class protect_t
{
public:
    typedef typename F::result_type result_type;

    explicit protect_t(F f): f_(f) {}

    template <typename... Args>
    result_type operator()(Args&&... args)
    {
        return f_(std::forward<Args>(args)...);
    }

private:
    F f_;
};

template <typename F>
protect_t<F> protect(F f)
{
    return protect_t<F>(f);
}

// compilation fails with libc++
template <typename F>
int fix2(F f, int c)
{
    return bind(protect(f), c)();
    // F copy(f);    // fails due to this!
}

#include <iostream>

int main()
{    
    std::cout << yeah(bind(sum, _1, 4), 5) << std::endl;  // works
    std::cout << nope(bind(sum, _1, 4), 5) << std::endl;  // breaks
    std::cout << fix1(bind(sum, _1, 4), 5) << std::endl;  // fixes
    std::cout << fix2(bind(sum, _1, 4), 5) << std::endl;  // doesn't compile
}

Wrapping the bind expression in a std::function (see fix1 ) remedies the problem, albeit by sacrificing speed due to run-time polymorphism disabling inlining (haven't measured it though).

Wrapping the bind expression in protect_t (see fix2 ) is inspired by boost::protect , however, compilation with libc++ fails due to bind expressions not being copyable. Which makes me wonder why wrapping them in std::function works anyway.

Any idea how to solve this problem? What's wring with std::bind anyway? First I thought the problem is related to eager evaluation of bind expressions dictated by the C++11 standard (see here ), but that would not be a problem here, would it?

The standard says that any callable can be wrapped using std::bind , including those produced by a preceding call to std::bind . Your problem is caused by a deficiency in the implementation of the standard library you're using, the solution is either to upgrade or, if this bug isn't still fixed, to switch to a different implementation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM