为什么没有std :: protect?

K-b*_*llo 24 c++ c++11

为什么在C++ 11中没有std::protect和它一起使用?std::bind

Boost.Bind提供了一个boost::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)));
}
Run Code Online (Sandbox Code Playgroud)

Dav*_*e S 15

好吧,我不知道它为什么没有实施.也许它没有提出,或者也许有一些微妙的陷阱.

那就是说,我认为你可以很容易地写出来

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));
}
Run Code Online (Sandbox Code Playgroud)

保护的两个版本是这样的,非绑定表达式不会被包装(它们只是通过).其他所有内容都通过移动/复制传递给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;

}
Run Code Online (Sandbox Code Playgroud)

  • 使用C++ 11继承构造函数,整个类定义只是`template <typename T> struct protect_wrapper:T {using T :: T; };` (10认同)