2013-08-29 37 views
24

C++ 11std::protect ile birlikte kullanmak için std::bind birlikte kullanım yok mu?Neden std :: protect yok?

Boost.Bindboost::bind tanımak ve değerlendirmek kalmaması onun argüman sarar bir boost::protect yardımcısı sağlar. std::[c]ref, çoğu zaman yeterince iyi bir yedek olacaktır, ancak argüman olarak bir rvalue almaz. Bunun uygulanmadı neden farkında değilim, Eh

#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

Önerilen miydi? –

+1

Bir “rıhtım” üzerindeki bir “cref” muhtemelen büyük olasılıkla felaket olurdu - geçici ömürler, “bind” nesnesine geçirildiği sürece (ya da her neyse) geçtiği sürece onu küçük tutar. – Yakk

+0

Ayrıca, çalışma zamanı yükünü eklese de, 'bind' sonucunu' std :: function' olarak atayarak "koruyabilirsiniz". – Potatoswatter

cevap

14

:

somut Örneğin, aşağıdaki suni durumu göz önünde bulundurun. Belki de önerilmiyordu, ya da belki bazı ince tuhaflıklar vardı. sözü

, sana oldukça kolay koruma iki sürümü böylece olmayan bağlama ifadeleri (onlar sadece geçmesine) sarılmış değil mi

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)); 
} 

yazabilirsin düşünüyorum. Diğer her şey, taşıma/kopyalama yoluyla yalnızca türden miras alan protect_wrapper'a geçirilir. Bu, türün işlevlerinin geçmesine veya türüne dönüştürülmesine olanak tanır.

Kopyalama/taşıma yapar, bu nedenle rvallerle güvenle kullanılabilir. Ve sadece bind_expressions olan türleri koruduğu için, gerçekleşmesi gereken kopyalama miktarını en aza indirir.

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 devralma yapıcıları ile, tüm sınıf tanımı sadece 'şablon struct protect_wrapper'tır: T {T :: T kullanarak; }; '' – Potatoswatter

+0

Bana öyle geliyor ki, destek :: korumanın amacı, insanlara ulaşılamaz bir kod yazabilmektir… Bir lambda ifadesi bu kadar karmaşıksa, onu yeniden düzenleme zamanı geldiğini söylemek adil olmaz mıydı? –

+0

@RichardHodges: Nadir olsa da, "destekleme" komutunun amacının, bind'lerin genellikle yuvalanmış bağları nasıl işlediğini anlatmadan, bir argüman işlevi gören bir işlev yazmanıza izin verdiğimi düşünüyorum. C++ 'da başka bir işlev alan bir işlev olmamakla birlikte, normal olanı bulmak için daha işlevsel programlama stilleri vardır. –