2014-01-18 28 views
3

为什么输出是0003212?为什么不使用我的(模板)构造函数进行初始化?

#include <iostream> 
using namespace std; 

template<typename X> class C 
{ 
public: 
    C() { cout<<"0";} 
    template<class T> C(const C<T>& c) { cout<<"1";} 
    C(const C<int>& c) { cout<<"2";} 
    template<class T> C(const C<T*>& c) { cout<<"3";} 
}; 

int main(int argc, char* args[]) 
{ 
    C<int> c1;   // 0 
    C<double> c2;  // 0 
    C<int*> c3;   // 0 

    C<int> c4(c3);  // 3 
    C<int> c5(c1);  // 2 
    C<int> c6(c2);  // 1 
    C<float> c7(c1); // 2 
    C<double> c8(c2); // ? 

    std::cin.get(); 
    return 0; 
} 

什么是在最后的意义线中调用?

我可以假设它的一些自动创建的构造函数 但不能找出哪一个。

+0

:不,模板的构造函数永远不能取代的拷贝构造函数。而默认的拷贝构造函数'C :: C(const C &)'比'c8'初始化更适合比任何模板。 –

+0

你 Ç :: C(常量ç&) 和我 模板 C(常量ç&C){COUT << “1”;} 是不是一回事? – Papirosnik

+0

不,他们不是。我会添加一个解释原因的答案。 –

回答

5

这里有几种C++语言规则。

  1. 模板不能是复制构造函数。 (标准规则12.8p2)

    非模板构造为X类是一个拷贝构造如果第一个参数是X&类型,常量X&volatile X&const volatile X&的,并且或者没有其他参数或否则所有其他参数都有默认参数。

  2. 如果没有定义拷贝构造函数,编译器会生成一个默认值(如果可能的话)。 (标准规则12.8p7)

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

    struct X { 
        X(const X&, int); 
    }; 
    

    复制构造函数是隐式声明的。如果后面将用户声明的构造函数定义为X::X(const X& x, int i =0) { /∗ ... ∗/ } ,则由于含糊不清造成对X的复制构造函数的任何使用都是不合格的;不需要诊断。

  3. 如果模板和非模板对参数同等匹配,则非模板获胜。 (标准规则13.3.3)的规则是一个很大的难以消化的混乱,我将只显示重要的部分:

    [...]可行的功能F1被定义为一个更好的功能比另一个可行的功能F2如果[...关于参数匹配的规则...]或者,如果不是那样的话,F1是非模板函数并且F2是功能模板专门化[...]

从你提供的代码,只有

C<int>::C(const C<int>&) 

是用户定义的拷贝构造函数,打印2。除int以外的所有X都没有定义复制构造函数,因此编译器会创建一个。

又见@ H2CO3

+0

你的规则听起来像是真的) 我继续试验,现在明白了哪些ctors被使用。 你写的规则很好地解释了我的情况,但有一个小问题... 他们是在C++的standratd? – Papirosnik

+0

@ user2032538:我已经解释了标准以便于理解,但我可以在标准中找到实际的措词。 –

+0

这个答案比接受的要好得多...... :(太少upvotes,太多无知...... :( – 2014-01-18 22:38:19

4

它是由编译器为您生成的复制构造函数,并且因为它是最好的匹配项,所以它在最后一种情况下被选中。

+0

c6的类型是C ,而c2的类型是C 。就编译器而言,这些将完全分离类。因此,要找到使用哪个ctor,编译器需要考虑ctors(生成可能的匹配列表)。第一个显然不好。第二个可能工作。第三个从实际参数(C )取不同类型(C ),因此不正确。最后一个也不好,因为它采取的形式是C ,它不符合C 。所以这种情况只有一种可能的匹配。 – tumdum

+0

你是对的 我设法看到asm列表中生成的构造函数的路径。 现在我明白发生了什么) 非常感谢 – Papirosnik

0

在最后一种情况下,您会调用默认拷贝构造函数。

相关问题