C++ 初始化忽略构造函数模板
在追求一些错误的过程中,我偶然发现了以下初始化行为,这对我来说似乎很奇怪:当对现有构造函数进行初始化检查时,似乎有一些情况是忽略了适合构造函数的模板。例如,考虑以下程序:C++ 初始化忽略构造函数模板,c++,templates,constructor,initialization,C++,Templates,Constructor,Initialization,在追求一些错误的过程中,我偶然发现了以下初始化行为,这对我来说似乎很奇怪:当对现有构造函数进行初始化检查时,似乎有一些情况是忽略了适合构造函数的模板。例如,考虑以下程序: #include <iostream> template<class T> struct A { A() {}; template<class S> A(const A<S>& a) {std::cout << "constructor templat
#include <iostream>
template<class T>
struct A {
A() {};
template<class S>
A(const A<S>& a) {std::cout << "constructor template used for A" << std::endl;};
};
template<class T>
struct B{
B() {};
B(const B<int>& b) {std::cout << "constructor used for B" << std::endl;};
};
int main() {
A<int> a;
B<int> b;
A<int> aa = a;
B<int> bb = b;
A<double> aaa = a;
}
这意味着它不在main的第三行中使用构造函数。为什么不呢?有什么原因吗?还是我的语法有问题?该模板似乎工作正常,因为它在最后一行中成功使用
我知道这个例子看起来太复杂了,但是各种各样的简化使得我想要显示的行为消失了。另外:初始化将使用模板专门化,这是我目前防止这种情况导致错误的方法(它首先导致了错误)
很抱歉,如果我的问题以任何方式被取消,我不是程序员,我不是母语人士,这是我的第一个问题,请原谅。这是因为模板化的ctor不是复制ctor。另请参见。编译器提供了一个隐式声明的非模板副本构造函数,其签名等效于
A(const A& a);
因为模板构造函数不被视为用户定义的副本构造函数,即副本构造函数必须是非模板
隐式声明的复制构造函数在重载解析中比模板版本更匹配,并且是从a
复制a
时调用的构造函数。这可以用一个简单的例子来说明,用户定义的a(const a&)
:
#包括
模板
结构A
{
A(){};
A(常数A&A){
std::cout根据C++11标准第12.8/7段:
如果类定义没有显式声明副本构造函数,则隐式声明副本构造函数
此外,根据第12.8/2段:
类X的非模板构造函数如果其第一个参数的类型为X&,const X&,则它是一个复制构造函数,
volatile X&或const volatile X&,或者没有其他参数,或者没有其他所有参数
具有默认参数(8.3.6)
因此,编译器将在此处生成一个隐式复制构造函数,该构造函数在执行此行时被调用:
A<int> aa = a;
aa=A;
这解释了为什么看不到相应的输出。第3行使用复制构造函数,而不是默认构造函数,后跟赋值。当询问“为什么它执行X而不是Y”时这有助于告诉你为什么你认为它应该做Y。对许多人来说,做X可能太明显了,以至于他们从来没有想过Y会发生。这个解释可以应用于任何函数,但我认为它并没有进入这个特定案例的核心:为什么编译器会自动生成一个可以生成的独立副本构造函数来自模板构造函数的d。好吧,看起来OP不同意,这对我来说很好:)@Gorpik你是对的,我没有解释。我添加了几行(希望)澄清。我仍然对他们为什么选择不接受构造函数表单模板作为复制构造函数感兴趣。@user211577这可能是由于模板函数(成员或其他)的缘故在实例化之前不存在。因此,副本构造函数在使用之前不存在。因此编译器无法知道是否存在副本构造函数,因此必须提供隐式生成的副本构造函数。在某些元编程情况下,需要知道类型在编译时是否有副本构造函数。谢谢您的回答。如我只能接受一个答案,而另一个答案是第一个,你将不得不接受。我很抱歉。@user211577:没问题,但没有任何东西强迫你接受你得到的第一个答案,你可以随时改变主意:-)然而,这并不是说你应该接受这个答案:你接受的答案是正确的,很好。我试图接受这两个答案。…所以我知道我可以改变主意。还有一个问题,为什么不允许将模板用作复制构造函数是有意义的(请参见接受答案中的讨论)。如果您碰巧知道…@user211577:我想原因是编译器不可能事先知道您的类是否有副本构造函数。在您的特定情况下,构造函数模板接受任何模板参数,因此这很好,但通常模板的实例化可能会因某些参数而失败,例如nd它失败的参数很可能是那些在使用时实例化副本构造函数的参数。在一般情况下,编译器无法进行语义分析并提前确定是否存在生成副本构造函数的有效替换。@user211577:但可能还有其他(更好的?)原因。我只是想猜测一下。
#include <iostream>
template<class T>
struct A
{
A() {};
A(const A& a) {
std::cout << "copy constructor used for A" << std::endl;
}
template<class S>
A(const A<S>& a) {
std::cout << "constructor template used for A" << std::endl;
}
};
int main()
{
A<int> ai;
A<double> ad = ai; / calls template conversion contructor
A<int> ai2 = ai; // calls copy constructor A(const A&);
}
A<int> aa = a;