使lambda不可复制/不可移动

时间:2020-02-20 08:43:15

标签: c++ lambda

请考虑以下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不可复制或不可移动,而无需显式捕获任何不可复制的变量(即将[]留空)?

1 个答案:

答案 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。