我正在学习 C++ 中的构造函数。特别是,一个 C++ 类可以有多个构造函数。但是后来我制作了以下程序,它适用于 clang 但不适用于 gcc 和 msvc。
template<typename T>
struct A {
A() {}
A(A<bool>);
};
A<bool> a; //works with clang but not with gcc and msvc
//A<double> b; //works with all compilers
令人惊讶的是
A<bool> a;
只适用于clang并且被gcc和msvc拒绝但是A<double> b;
适用于所有3个编译器。
MCVC 说:
<source>(4): error C2652: 'A<bool>': illegal copy constructor: first parameter must not be a 'A<bool>'
<source>(4): note: see declaration of 'A<bool>'
<source>(6): note: see reference to class template instantiation 'A<bool>' being compiled
为什么我们会收到此错误以及根据 C++ 标准哪个编译器是正确的。
根据 C++20 标准 (11.4.5.3 Copy/move constructors)
5 如果类 X 的构造函数的声明是错误的 第一个参数是 cv X 类型,要么没有其他 参数或所有其他参数都有默认参数。 A 永远不会实例化成员函数模板来产生这样的 构造函数签名。
因此,当类型模板参数是
bool
用于模板类的实例化时,实际上您在该类实例化中具有以下构造函数
A( A );
错误信息
(4): error C2652: 'A': 非法拷贝构造函数: first 参数不能是“A”
指向这个为类的实例化而生成的格式错误的复制构造函数
A<bool>
.
另一方面,当类型模板参数是
double
(或其他东西)时,构造函数的这个声明
A( A<bool> )
因为类的这种实例化不会产生格式错误的复制构造函数,因为例如类型
A<double>
和A<bool>
是两种不同的类类型。
为了避免错误,在类模板中声明构造函数就足够了
template<typename T>
struct A {
A() {}
A(A<bool> &);
};
程序格式错误,无需诊断。这个可以从temp.res看到:
可以在任何实例化之前检查模板的有效性。 [注意:知道哪些名称是类型名称允许以这种方式检查每个模板的语法。 — 尾注]程序格式错误,不需要诊断,如果:
- a 紧随其定义的模板的假设实例化由于不依赖于模板参数的构造, 或
- 在假设实例中对这种构造的解释不同于在模板的任何实际实例中对相应构造的解释。 [注意:这可能发生在以下情况:
- a 非依赖名称中使用的类型在定义模板时不完整,但在执行实例化时完整, 或