使 lambda 不可复制/不可移动

3
考虑以下代码:链接
#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个回答

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 表达式更大。


1
不错!它还将允许C++20引入的无状态lambda的默认构造。 - n314159
你有检查过代码编译吗?它对我来说无法编译。看起来需要添加默认构造函数:NoCopyMove() = default; - αλεχολυτ
那么...我的尝试有什么问题吗(链接在我第一条评论中)?你能分享一下你可编译的代码版本吗? - αλεχολυτ
1
@sweenish 这是 类模板参数推导 的一部分。 - αλεχολυτ
@αλεχολυτ - 区别在于我将代码编译为C++17(https://wandbox.org/permlink/zcUqB4OMrbNkIL2P),而您将其编译为C++2a。似乎初始化规则已经改变了。目前我还不确定具体情况。但是,如果C++20需要一个默认的默认构造函数来处理`NoCopyMove`,那么这种惯用法就没有太大区别了。 - StoryTeller - Unslander Monica
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接