5

ネストされた式を呼び出すときに問題が発生し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とにかく何をしているのですか?最初に、問題はC ++ 11標準(ここを参照)によって規定されたバインド式の熱心な評価に関連していると思いましたが、それはここでは問題ではないでしょうか?

4

1 に答える 1

0

std::bind標準では、の前の呼び出しによって生成されたものを含め、すべての呼び出し可能オブジェクトは、を使用してラップできるとされていstd::bindます。問題の原因は、使用している標準ライブラリの実装の欠陥です。解決策は、アップグレードするか、このバグがまだ修正されていない場合は、別の実装に切り替えることです。

于 2012-09-30T09:43:01.143 に答える