【发布时间】:2013-08-29 19:02:33
【问题描述】:
为什么在C++11中没有std::protect与std::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)));
}
【问题讨论】:
-
有人提出来了吗?
-
cref上的rvalue可能会是灾难性的——只要将它传递给的bind对象(或其他),临时生命周期几乎不会保留它。 -
您也可以通过将
bind结果分配给std::function来“保护”,尽管这会增加运行时开销。 -
C++11
<functional>是从 TR1 库演变而来的,TR1 库是一个独立于 2006 年左右的 C++ 的 ISO 标准,它从 Boost 中采用。所以你可能会看到一些不同的演变。 -
也许更好的名字是
std::hold(如reference.wolfram.com/language/ref/Hold.html)。在我看来,如果有一个叫做std::protect的东西对我来说意味着一个明确的cast-to-const。并不是说我总是为此编写一个也称为protect的函数:)。换句话说,我想知道protect一开始是不是一个坏名字。