显式副本构造函数的行为

问题描述

我有以下代码

#include <iostream>

struct A {
  A(int x=1,int y=1) : x(x),y(y) { }
  A(const A& other) : x(other.x),y(other.y) { }

  operator bool() const { return !x && !y; }

  friend std::ostream& operator<<(std::ostream& os,const A& a) {
    os << a.x << "," << a.y << "\n";
    return os;
  }

  int x;
  int y;
};

int main(int argc,char const *argv[]) {
  A const A10x10(10,10);
  A a;
  std::cout << a;
  A aa = A10x10;
  std::cout << aa;
  return 0;
}

上面的照片:

1,1
10,10

当我将复制构造函数更改为显式(即explicit A(const A& other);)时,我得到:

1,1
0,1

我在(显式)复制构造函数中放置了一条print语句,实际上它并未被调用。为什么会这样呢? explicit有什么区别?

我正在使用C ++ 17,并使用Clang10进行编译。

解决方法

此:

A aa = A10x10;

执行复制初始化。复制初始化通过将对象转换为要初始化的对象的类型来工作。但是,副本初始化通过隐式转换来实现。隐式转换不能调用explicit构造函数。

即使是复制构造函数。

现在,按所有权利,您会认为会遇到编译错误。但是你没有。为什么?因为A可以通过用户定义的转换隐式转换为boolbool可通过标准转换转换为int。实际上,A可以由类型为int的单个值构造。尽管隐式转换仅允许一个用户定义的转换,但它确实允许用户定义的转换以及随后的标准转换。

这就是发生的情况。这就是为什么当复制构造函数为aaexplicit中的第一个值为0的原因。

通常来说,总是设为operator bool explicit。并且从不使副本构造函数explicit