为什么没有std :: protect?

时间:2013-08-29 19:02:34

标签: c++ c++11

C ++ 11 中为什么没有std::protectstd::bind一起使用?

Boost.Bind 提供了一个boost::protect帮助程序,它包装了它的参数,以便boost::bind无法识别和评估它。 std::[c]ref在大多数情况下都是一个足够好的替代品,除了它不会将 rvalue 作为参数。

举一个具体的例子,考虑以下人为情况:

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

1 个答案:

答案 0 :(得分: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));
}

两个版本的保护是为了不包装非绑定表达式(它们只是通过)。其他所有内容都通过移动/复制传递给protect_wrapper,而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; } 只是从类型继承而来。这允许类型的函数通过,或者转换为类型。

它会进行复制/移动,因此可以安全地与rvals一起使用。因为它只保护bind_expressions类型,所以它最大限度地减少了必须发生的复制量。

{{1}}