我看到一个类似的问题Default move constructive taking a const parameter,这个问题已经有 8 年了,答案是 No。
但同时,稍微修改一下程序,在类定义之后默认使用构造函数:
struct A {
A(const A&&);
};
A::A(const A&&) = default;
已被EDG 6.7接受,并于近期发布了GCC 15.1。在线演示:https://gcc.godbolt.org/z/E4qT3sTEq
甚至更复杂的例子似乎也可以在这两个编译器上正常工作:
struct A {
int i;
constexpr A(int v) : i(v) {}
constexpr A(const A&&);
};
constexpr int f() {
A a(1);
A b = static_cast<const A&&>( a );
return b.i;
}
constexpr A::A(const A&&) = default;
static_assert( f() == 1 );
但 MSVC 仍然不喜欢它:
error C2610: 'A::A(const A &&)': is not a special member function or comparison operator which can be defaulted
<source>(13): note: the argument must be a non-const rvalue reference
以及 Clang:
error: the parameter for an explicitly-defaulted move constructor may not be const
在线演示:https://gcc.godbolt.org/z/6W9W865vG
过去8年里,这方面有什么变化吗?现在哪种实现方式是正确的?
[dcl.fct.def.default]中的规则是:
隐式声明的移动构造函数看起来像
A(A&&)
。A(A const&&)
与 的不同之处在于它不符合上述四个例外中的任何一个(将复制构造函数定义为 是一种特殊情况C(C&) = default;
,这是第四个项目符号,但对于移动构造函数则没有)。所以我们落入了第二条规则。如果这个移动构造函数在第一次声明时就被默认了,它就会被定义为已删除。但在原帖中,它的默认设置是不合逻辑的——所以这应该是格式错误的。
在 C++17 中(与C++14类似),这仍然是格式错误的(即使函数在第一次声明时就被默认了)。因此,虽然关于默认的规则已经有所放宽,但这些放宽不会影响这个例子。