在 lambda 捕获的对象中选择移动构造函数

selecting a move-constructor in a lambda-captured object

作为测试,class 定义了复制构造函数并显式删除了移动构造函数,因此无法移动构造对象。

struct foo {
    foo()=default;
    foo(const foo&) { std::cout << "foo copied\n"; }
    foo(foo&&)=delete;
};

foo f;
foo a = f;        // ok
foo b = move(f);  // fails (expected)

据我了解,当显式删除移动构造函数时,其声明仍然存在于重载过程中,这就是无法构造 foo b 的原因。 仅定义复制构造函数时,不会声明移动构造函数,并且复制构造函数 const foo& 参数将接受右值。

但是,当我将对象放入 lambda 时,它会编译:

foo f;
auto lmb = [f]() { }; // f copied into the closure object

auto x = std::move(lmb);

lambda 被转换为右值,但它持有的对象仍然被复制(根据输出)。
(当定义 foo 移动构造函数时,它会按预期被调用)。

问题:为什么未选择(已删除)foo 移动构造函数(因此无法编译)?

Question: why is the (deleted) foo move-constructor not selected (so that it fails to compile) ?

因为 lambda 的定义是默认的,而不是显式删除,因此重载解析被调整为忽略它。

[over.match.funcs.general]

8 A defaulted move special member function ([class.copy.ctor], [class.copy.assign]) that is defined as deleted is excluded from the set of candidate functions in all contexts.

它 hard-coded 自 C++11 以来的语言,并引入了移动语义。否则,在移动操作可用之前编写的旧代码(并且会隐式删除移动操作)将在升级时悄无声息地中断。不好。