Meh*_*dad 3 c++ move-constructor move-semantics c++11 c++17
以下代码S通过const &&.
然而它返回0,表明S不可移动构造!
main根据标准,2 个标记结构中每一个的正确行为是什么?
如果返回0是正确的行为,其背后的原理是什么?
(为什么它不应该反映类型实际上是否可以通过移动构造?)
#include <algorithm>
struct S
{
S( ) { }
S(S &) { } // = delete; doesn't make any difference
S(S const &) { } // = delete; doesn't make any difference
S(S const &&) { }
S(S &&) = delete;
};
int main()
{
S const s1;
S s2(std::move(s1)); // OK for >= C++11
S s3((S())); // OK for >= C++17, error for <= C++14
static_assert(std::is_move_constructible<S>::value);
}
Run Code Online (Sandbox Code Playgroud)
尽管标准认为S(const S&&)是“移动构造函数”并且您可能认为这将是它的结束,但is_move_constructible实际上要求您的声明s3在 C++14 及更早版本中有效;即将为该声明选择一个移动构造函数。
如果
T不是可引用类型(即,可能是cv 限定的void或具有cv-qualifier-seq或ref-qualifier的函数类型),则提供等于 的成员常量值false。否则,提供等于 的成员常量值std::is_constructible<T, T&&>::value。
您遇到的问题是S(S&&)仍然可以通过重载解析找到。发生这种情况,S(S&&)比S(const S&&),更好的匹配S(S&&)被发现被删除。
s3的声明在 C++17 中有效只是因为它根本没有复制或移动。曾经是临时对象的“声明”现在只是构造函数参数的花哨列表;当且仅当需要一个匹配的临时对象时,它才会在调用堆栈的更下方“具体化”。这被称为“保证省略”,即使根本没有临时真正被省略,因为它根本就不存在。
请记住,移动语义是一种错觉;您真正要做的就是让语言“调用函数”,并为您作为参数提供的表达式使用适当的参数。s2之所以有效,是因为您传递了一个右值 const S(通过提供 a 形成的表达式的值类别和类型const S&&),它可以绑定到 a const S&&(但不能绑定到 a S&&!);这是否算作“移动构建就好”是一个观点问题。
tl; dr:该特征需要S(S&&)起作用,而您明确定义了它不能起作用。
| 归档时间: |
|
| 查看次数: |
111 次 |
| 最近记录: |