2013-08-29 9 views
24

std::bindと一緒に使用するstd::protectがない理由は、にあります。C++ 11std :: protectがないのはなぜですか?

Boost.Bindboost::bindがそれを認識し、評価しないように、その引数をラップboost::protectヘルパーを提供します。 std::[c]refは、ほとんどの場合、十分に置換えられますが、の値のを引数に取ることはありません。私はそれが実装されなかった理由を認識していないよ、まあ

#include <type_traits> 
#include <functional> 

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

struct invoke_with_42 
{ 
    template <typename FunObj> 
    auto operator()(FunObj&& fun_obj) const -> decltype((fun_obj(42))) 
    { return fun_obj(42); } 
}; 

int main() 
{ 
    //// Nested bind expression evaluated 
    //auto bind_expr = 
    // std::bind<int>(invoke_with_42{} 
    //  , std::bind(&add, 1, std::placeholders::_1)); 

    //// Compilation error, cref does not take rvalues 
    //auto bind_expr = 
    // std::bind<int>(invoke_with_42{} 
    //  , std::cref(std::bind(&add, 1, std::placeholders::_1))); 

    //// Ok, inner_bind_expr must be kept alive 
    auto inner_bind_expr = 
     std::bind(&add, 1, std::placeholders::_1); 
    auto outer_bind_expr = 
     std::bind<int>(invoke_with_42{}, std::cref(inner_bind_expr)); 


    //// Ok, with protect 
    //auto bind_expr = 
    // std::bind<int>(invoke_with_42{} 
    //  , std::protect(std::bind(&add, 1, std::placeholders::_1))); 
} 
+10

提案されましたか? –

+1

'rvalue'の' cref'はおそらく悲惨です。一時的な生涯は 'bind'オブジェクトが渡されている間はほとんど保持されません。 – Yakk

+0

また、ランタイムオーバーヘッドを追加しますが、 'bind'結果を' std :: function'に割り当てることで "保護"することもできます。 – Potatoswatter

答えて

14

は、具体的な例については、以下の人工的な状況を考えます。おそらく、それは提案されていないか、あるいはおそらく微妙な問題がありました。言っ

は、私はあなたがかなり簡単にプロテクトの2つのバージョンがように非バインド式は、(彼らは単に通過)ラップされていないです

template<typename T> 
struct protect_wrapper : T 
{ 
    protect_wrapper(const T& t) : T(t) 
    { 

    } 

    protect_wrapper(T&& t) : T(std::move(t)) 
    { 

    } 
}; 

template<typename T> 
typename std::enable_if< !std::is_bind_expression< typename std::decay<T>::type >::value, 
       T&& >::type 
protect(T&& t) 
{ 
    return std::forward<T>(t); 
} 

template<typename T> 
typename std::enable_if< std::is_bind_expression< typename std::decay<T>::type >::value, 
       protect_wrapper<typename std::decay<T>::type > >::type 
protect(T&& t) 
{ 
    return protect_wrapper<typename std::decay<T>::type >(std::forward<T>(t)); 
} 

それを書くことができると思います。他のすべてはmove/copyによってprotect_wrapperに渡されます。これは単に型を継承します。これにより、型の関数を通過させるか、型に変換することができます。

しかし、それはコピー/移動を行うので、安全に使用することができます。また、bind_expressions型のみを保護するため、発生する必要があるコピーの量が最小限に抑えられます。

int main() 
{ 

    //// Ok, with protect 
    auto bind_expr = 
     std::bind<int>(invoke_with_42{} 
      , protect(std::bind(&add, 1, std::placeholders::_1))); 


    std:: cout << bind_expr() << std::endl; 
    return 0; 

} 
+10

C++ 11のコンストラクタを継承すると、クラス定義全体は 'template struct protect_wrapper:T {T :: Tを使用しています。 }; ' – Potatoswatter

+0

boost :: protectの目的は、メンテナンス可能なコードを書くことができるようにすることです...ラムダ式がこの複雑な場合、それをリファクタリングする時でしょうか? –

+0

@RichardHodges:これはまれですが、 'boost :: protect'の目的は、' bind'が通常ネストされたバインドをどのように処理するかを調べることなく、関数を引数として取る関数を書くことができるようにするためです。別の関数を取る関数がC++では一般的ではないが、それを見つけるためのより多くの関数型プログラミングスタイルが存在する。 –

関連する問題