在 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 以来的语言,并引入了移动语义。否则,在移动操作可用之前编写的旧代码(并且会隐式删除移动操作)将在升级时悄无声息地中断。不好。
作为测试,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 以来的语言,并引入了移动语义。否则,在移动操作可用之前编写的旧代码(并且会隐式删除移动操作)将在升级时悄无声息地中断。不好。