首页 > 解决方案 > 如果在 C++17 中“删除”或“未声明”移动/复制构造函数/赋值,是否已确定?

问题描述

我正在查看有关自动生成移动操作的规则是什么,并且我希望现在答案已经很好地确定了。

根据类中已声明的内容,显示哪些构造函数/赋值运算符“未声明”、“默认”或“已删除”的幻灯片显示:

在此处输入图像描述

这是从这些幻灯片中获取的,红色方块表示此行为已被弃用。

编译以下内容时:

#include <iostream>
struct X
{
  template<typename...T>
  X(T&&...) {
    std::cout << "Yay!\n";
  }

  ~X() {}
};

int main() {
  X x0;
  X x1{x0};
  X x2{std::move(x0)};
}

看起来它们已经“未声明”,因为它编译并且输出是“Yay!” 三倍(这很好,至少对我来说)。但我想确认我可以依赖这种行为。

编辑

Frank已经指出,如果还添加了复制构造函数,它仍然会说“耶!” 三次,这是有趣的行为。做进一步的测试,如果添加了移动构造函数,它只会说“耶!” 两次。谁能解释这种行为?

标签: c++language-lawyerc++17

解决方案


根据 N4659(几乎是 C++17 标准),它们仍被定义为默认值,但行为(仍然)被弃用。

如果类定义没有显式声明复制构造函数,则隐式声明非显式构造函数。如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制构造函数定义为已删除;否则,它被定义为默认值。如果类具有用户声明的复制赋值运算符或用户声明的析构函数,则不推荐使用后一种情况。

如果类定义没有显式声明复制赋值运算符,则隐式声明一个。如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制赋值运算符被定义为删除;否则,它被定义为默认值。如果类具有用户声明的复制构造函数或用户声明的析构函数,则不推荐使用后一种情况。


推荐阅读