2013-08-29 3 views
24

C++ 11 std::bind와 함께 사용 할 std::protect이 없다?std :: protect가없는 이유는 무엇입니까?

부스트. 바인딩boost::bind이 인식하고 평가하지 않도록 해당 인수를 래핑하는헬퍼를 제공합니다. 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

:

는 구체적인 예를 들어, 다음과 같은 인공적인 상황을 고려한다. 아마 그것이 제안되지 않았거나, 아마도 미묘한 결함이있었습니다. 말했다

, 난 당신이 아주 쉽게 보호의 두 가지 버전이 그래서 비 바인드 표현식 (그들은 단지 통과) 포장되지 않은 있습니다

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

을 쓸 수 있다고 생각합니다. 그 밖의 모든 것은 이동/복사를 통해 protect_wrapper으로 전달됩니다. protect_wrapper은 단순히 유형을 상속합니다. 이렇게하면 형식의 함수가 전달되거나 해당 형식으로 변환 할 수 있습니다.

그것은 사본/그러나 이동한다, 그래서 안전하게 rvals 사용할 수 있습니다. 또한 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

는 전체 클래스 정의는'템플릿 구조체 protect_wrapper입니다 : T {T :: T를 사용하여; };' – Potatoswatter

+0

boost :: protect의 목적은 사람들이 유지 보수 할 수없는 코드를 작성할 수있게하는 것입니다 ... 람다 표현식이이 복잡한 경우 리팩토링 할 때가 되었습니까? –

+0

@RichardHodges : 드물지만, boost :: protect의 목적은'bind '가 일반적으로 중첩 된 바인드를 처리하는 방법을 바꾸지 않고 함수를 인수로 취하는 함수를 작성할 수 있도록하는 것이라고 생각합니다. C++에는 다른 함수를 사용하는 함수가 하나도 없지만 더 일반적인 함수 스타일이 있습니다. –

관련 문제