实际上,我确实编写了一个小实用程序来创建延迟调用函子(有点类似std::bind
,但没有嵌套的绑定表达式/占位符功能)。我的主要动机是这个我发现违反直觉的案例:
using pointer_type = std::unique_ptr<int>;
pointer_type source();
void sink(pointer_type p);
pointer_type p = source();
// Either not valid now or later when calling bound()
// auto bound = std::bind(sink, std::move(p));
auto bound = std::bind(
[](pointer_type& p) { sink(std::move(p)); }
, std::move(p) );
bound();
该适配器(将其左值 ref 参数移动到sink
)的原因是调用包装器 return bystd::bind
总是将绑定的参数作为左值转发。在 C++03 中这不是问题,boost::bind
因为左值要么绑定到底层 Callable 对象的引用参数,要么通过副本绑定到值参数。在这里不起作用,因为pointer_type
只能移动。
我得到的见解是,确实有两件事需要考虑:绑定的参数应该如何存储,以及它们应该如何恢复(即传递给 Callable 对象)。授予您的控制std::bind
如下:参数以浅层(通过使用std::ref
)或常规方式(使用std::decay
完美前向)存储;它们总是被恢复为左值(从拥有的调用包装器继承的 cv 限定符)。除了你可以像我刚刚做的那样用一个小的现场适配器 lambda 表达式绕过后者。
它可以说是大量的控制和大量的表达,而学习相对较少。相比之下,我的实用程序具有如下语义bind(f, p)
(衰减和存储副本,恢复为左值),bind(f, ref(p))
(浅层存储,恢复为左值),bind(f, std::move(p))
(从移动中衰减和存储,恢复为右值),bind(f, emplace(p))
(从移动中衰减和存储,恢复为左值) . 这感觉就像学习 EDSL。