Цепной вызов С++ 11 std::bind не работает

У меня проблема при вызове вложенных выражений std::bind. Следующий код демонстрирует проблему. Он не компилируется с libc++, но работает с 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
}

Обертывание выражения привязки в std::function (см. fix1) решает проблему, хотя и жертвует скоростью из-за полиморфизма во время выполнения, отключающего встраивание (хотя это не измерялось).

Обертывание выражения привязки в protect_t (см. fix2) вдохновлено boost::protect, однако компиляция с помощью libc++ завершается ошибкой из-за невозможности копирования выражений привязки. Что заставляет меня задаться вопросом, почему обертывание их в std::function все равно работает.

Любая идея, как решить эту проблему? Что вообще не так с std::bind? Сначала я подумал, что проблема связана с нетерпеливой оценкой выражений привязки, продиктованных стандартом С++ 11 (см. здесь), но это не было бы проблемой здесь, не так ли?


person marton78    schedule 20.08.2012    source источник
comment
У меня работает (используя libc++). Я бы посоветовал обновиться до более новой версии.   -  person Mankarse    schedule 20.08.2012
comment
Вы также копируете f в fix1, поэтому я подозреваю, что что-то еще является подделкой.   -  person Xeo    schedule 20.08.2012
comment
работает с gcc 4.7 liveworkspace.org/code/1b592f87c00b34fe4de13ba87ac0b8af   -  person ForEveR    schedule 20.08.2012
comment
какую версию g++ вы используете для компиляции?   -  person BЈовић    schedule 20.08.2012
comment
Голосование на закрытии, так как вопрос не имеет решения.   -  person Kerrek SB    schedule 03.09.2012


Ответы (1)


Стандарт говорит, что любой вызываемый объект может быть обернут с помощью std::bind, в том числе созданные предыдущим вызовом std::bind. Ваша проблема вызвана недостатком реализации стандартной библиотеки, которую вы используете, решение состоит в том, чтобы либо обновить ее, либо, если эта ошибка все еще не исправлена, переключиться на другую реализацию.

person Community    schedule 30.09.2012