【问题标题】:Why auto cannot be used to define an implicitly deleted constructor为什么不能使用 auto 来定义隐式删除的构造函数
【发布时间】:2022-11-21 14:09:08
【问题描述】:

我有这个小 sn-p(用 g++ 编译),我在其中定义了一个移动构造函数:

#include <iostream>
using namespace std;

class A {
public:
  A() = delete;
  A(int value) : value(value) {}
  void operator=(const auto &other) = delete;
  ~A() { cout << "Destructor called..." << endl; }

  A(const auto &other) {
    cout << "Copy constructor called..." << endl;
    value = other.value;
  }

  A(const A &&other) {
    cout << "Move constructor called..." << endl;
    value = other.value;
  }

private:
  int value;
};

int main() {
  A p1(2);
  A p2(p1);

  return 0;
}

问题是我得到main.cpp:27:10: error: use of deleted function 'constexpr A::A(const A&amp;)'

据我所知,有一个编译器约定在定义移动构造函数时隐式删除​​任何复制操作。如果用户需要它们,则必须明确定义它们。

但是,我尝试使用 auto 作为参数定义一个复制构造函数。如果构造函数签名是A(const A &amp;other),程序运行正常。

由于auto 将被解析为A,编译器仍然认为该特定构造函数已删除的原因是什么?

【问题讨论】:

  • 因为A(const auto &amp;other) 不能是拷贝构造函数。这类似于模板构造函数不能是复制构造函数的原因。
  • 如果删除移动构造函数,则看不到“Copy constructor called...”,因为 A(const auto &amp;other) 不是复制构造函数。
  • 由于 auto 将被解析为 A“:参数中带有占位符 (auto) 的“函数”声明不是函数,而是函数模板。它不会解析为 A。它将接受任何类型作为构造中的参数。正如答案所说,函数模板永远不能是复制构造函数,因此仍然存在被删除的隐式构造函数,并且在重载决策中更好地匹配(因为它不是模板)。

标签: c++ gcc


【解决方案1】:

由于 auto 将被解析为 A,编译器仍然认为该特定构造函数已删除的原因是什么?

因为 A::A(const auto &amp;) 不能像在函数参数中使用 auto 时那样是复制构造函数,所以该函数声明/定义实际上是针对函数模板的。根据class.copy.ctor,模板化构造函数不能是复制构造函数。

一个非模板构造器对于类X,如果它的第一个参数是X&amp;const X&amp;volatile X&amp;const volatile X&amp;类型,并且没有其他参数或者所有其他参数都有默认参数([dcl .fct.default])。

(强调我的)


【讨论】:

  • 您可能想要解释为什么选择隐式(已删除)复制构造函数而不是非复制构造函数。请参阅我在答案下的评论。
  • 不会出现任何重定义错误“:不确定这是一个好的测试。可能有多个具有不同签名/约束的复制构造函数。您只是在验证声明没有声明通常的声明。
猜你喜欢
  • 2018-10-05
  • 1970-01-01
  • 2018-06-17
  • 2015-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-16
相关资源
最近更新 更多