将局部变量绑定到闭包的最便宜的方法

mmo*_*rny 5 c++ c++11

我相信以下是将局部变量绑定到闭包的最便宜的方法:

void ByRValueReference(A&& a) {
}

std::function<void ()> CreateClosureByRValueReference() {
  A a;
  std::function<void ()> f = std::bind(&ByRValueReference, std::move(a)); // !!!
  return f;
}
Run Code Online (Sandbox Code Playgroud)

但是,它不能在Clang 3.1下编译:

error: no viable conversion from '__bind<void (*)(A &&), A>' to 'std::function<void ()>'
Run Code Online (Sandbox Code Playgroud)

和gcc 4.6.1:

/usr/include/c++/4.6/functional:1778:2: error: no match for call to ‘(std::_Bind<void (*(A))(A&&)>) ()’
Run Code Online (Sandbox Code Playgroud)

我违反了标准,还是只是破坏了标准库?

Luc*_*ton 3

这是设计使然std::bind。完整规范位于 20.8.9.1.2 函数模板绑定 [func.bind.bind] 中,但在本例中,第 10 段的最后一个项目符号(描述如何使用绑定参数)适用:

\n\n
\n

\xe2\x80\x94 否则,值为tid及其类型ViTiD cv &

\n
\n\n

换句话说,std::move(a)将导致调用包装器存储一个A(来自移动构造),然后在使用时,该成员将作为左值operator()转发(带有与调用包装器的 cv 限定符匹配的附加 cv 限定符,但我离题)。即使它作为右值传递。

\n\n

这种不匹配可以通过 lambda 来解决:

\n\n
std::bind([](A& a) { ByRValueReference(std::move(a)); }, std::move(a))\n
Run Code Online (Sandbox Code Playgroud)\n\n

可以说,更明确的是,对结果调用包装的进一步调用是可疑的(因为该A成员可能已被移出),但我不太喜欢std::bind整体的行为。

\n