请考虑以下code:
#include <iostream>
#include <thread>
int main() {
std::thread t;
const auto l = [x = std::move(t)]{};
decltype(l) m = std::move(l);
}
此代码无法与以下消息一起编译:
prog.cc: In function 'int main()': prog.cc:7:32: error: use of deleted function 'main()::<lambda()>::<lambda>(const main()::<lambda()>&)' 7 | decltype(l) m = std::move(l); | ^ prog.cc:6:37: note: 'main()::<lambda()>::<lambda>(const main()::<lambda()>&)' is implicitly deleted because the default definition would be ill-formed: 6 | const auto l = [x = std::move(t)]{}; | ^ prog.cc:6:37: error: use of deleted function 'std::thread::thread(const std::thread&)' In file included from prog.cc:2: /opt/wandbox/gcc-head/include/c++/10.0.1/thread:154:5: note: declared here 154 | thread(const thread&) = delete; | ^~~~~~
是否有一种方法可以使lambda不可复制或不可移动,而无需显式捕获任何不可复制的变量(即将[]
留空)?
答案 0 :(得分:7)
您可以编写一个简单的信封聚合,以防止移动和复制。
struct NoCopyMove {
NoCopyMove(NoCopyMove const&) = delete;
NoCopyMove(NoCopyMove&&) = delete;
void operator=(NoCopyMove const&) = delete;
void operator=(NoCopyMove&&) = delete;
};
template<class Functor>
struct Fixed : Functor, NoCopyMove {
using Functor::operator();
};
template<typename F>
Fixed (F&&) -> Fixed<std::decay_t<F>>;
要像这样使用
const auto l = Fixed{[]{}};
NoCopyMove
是一个简单的mixin,可禁用复制和移动。这样写可以使我们将Fixed
的专业化保持为简单的聚合。
所有Fixed
所做的工作都是将作为参数给出的函子作为基类(尽可能保证复制省略)作为基础进行继承/初始化。然后公开其operator()
。
由于不涉及任何成员(可能不在Functor
中),并且由于lambda可能无法从我们的自定义NoCopyMove
类继承,因此空基优化会启动无状态lambda。因此,对象不应大于初始化对象时使用的lambda。