Why is there no std::protect
to use together with std::bind
in C++11?
Boost.Bind provides a boost::protect
helper that wraps its argument so that boost::bind
does not recognize and evaluate it. std::[c]ref
would be a good enough replacement most of the times, except that it won't take an rvalue as argument.
For a concrete example, consider the following artificial situation:
#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))); }
Although kissing is considered to be low-risk when compared to intercourse and oral sex, it's possible for kissing to transmit CMV, herpes, and syphilis. CMV can be present in saliva, and herpes and syphilis can be transmitted through skin-to-skin contact, particularly at times when sores are present.
Birth control methods like the pill, patch, ring, and IUD are very effective at preventing pregnancy, but they do not protect against STDs and HIV. The most reliable way to avoid STDs is to not have vaginal, anal, or oral sex.
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; }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With