2013-08-29 15 views
24

Dlaczego nie ma std::protect do użycia z std::bind w C++ 11?Dlaczego nie ma std :: protect?

Boost.Bind zapewnia boost::protect pomocnika, która otacza swój argument tak że boost::bind nie rozpoznaje i ocenia je. std::[c]ref byłaby wystarczająco dobrym zamiennikiem przez większość czasu, z tym wyjątkiem, że nie będzie przyjmować argumentu rvalue.

Dla konkretny przykład, rozważmy następujący sztuczną sytuację:

#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

Czy to było proponowane? –

+1

'cref' na' rvalue' prawdopodobnie byłby katastrofalny - życie tymczasowe nie utrzymałoby go tak długo, jak obiekt "bind", do którego jest przekazywany (lub cokolwiek). – Yakk

+0

Możesz również "chronić", przypisując wynik 'bind' do' std :: function', ale dodaje on dodatkowe środowisko wykonawcze. – Potatoswatter

Odpowiedz

14

Cóż, nie jestem świadomy, dlaczego nie został wdrożony. Być może nie zostało to zaproponowane, a może były jakieś subtelne grzęźnie.

Mimo to, myślę, że można napisać go dość łatwo

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

Obie wersje protect są tak, że wyrażenia zakaz wiązania nie są owinięte (po prostu przejść). Cała reszta jest przekazywana przez przeniesienie/kopiowanie do protect_wrapper, która po prostu dziedziczy po typie. Umożliwia to przejście funkcji typu lub przekształcenie go w typ.

Wykonuje jednak kopiowanie/przenoszenie, dzięki czemu można go bezpiecznie używać z rundami. A ponieważ chroni tylko typy, które są wyrażeniami bind_, minimalizuje ilość kopiowania, która musi wystąpić.

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

Przy dziedziczeniu konstruktorów C++ 11 cała definicja klasy to po prostu 'template struct protect_wrapper: T {używając T :: T; }; ' – Potatoswatter

+0

Wydaje mi się, że celem" boost :: protect "jest umożliwienie pisania niezniszczalnego kodu ... Czy nie byłoby uczciwie powiedzieć, że jeśli wyrażenie lambda jest tak skomplikowane, to czas na jego refaktoryzację? –

+0

@RichardHodges: Chociaż jest to rzadkie, myślę, że celem 'boost :: protect' jest umożliwienie pisania funkcji, która przyjmuje funkcję jako argument, bez potykania się o to, jak" bind "zwykle obsługuje zagnieżdżone powiązania. Chociaż jedna funkcja, która bierze inną, nie jest powszechna w C++, istnieje więcej funkcjonalnych stylów programowania, które normalizują się. –

Powiązane problemy