Why is there no std::protect?
Solution 1:
Well, I'm not aware of why it wasn't implemented. Perhaps it wasn't proposed, or perhaps there were some subtle gotchas.
That said, I think you can write it pretty easily
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));
}
The two versions of protect are so that non-bind expressions are not wrapped (they just pass through). Everything else is passed by move/copy to the protect_wrapper
, which simply inherits from the type. This allows the type's functions to pass through, or for it to convert to the type.
It makes a copy/move however, so it can be safely used with rvals. And since it only protects types that are bind_expressions, it minimizes the amount of copying that has to occur.
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;
}