papirosnik
papirosnik

Reputation: 357

Why isn't this initialization using my (template) constructor?

Why the output is 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;
}

What is invoked in the last meaning line?

I can suppose that it's some auto-created ctor but can't figure out which one.

Upvotes: 3

Views: 187

Answers (3)

Ben Voigt
Ben Voigt

Reputation: 283634

There are several C++ language rules in play here.

  1. A template cannot be a copy constructor. (Standard rule 12.8p2)

    A non-template constructor for class X is a copy constructor if its first parameter is of type X&, const X&, volatile X& or const volatile X&, and either there are no other parameters or else all other parameters have default arguments.

  2. If no copy constructor is defined, the compiler generates a default one (if possible). (Standard rule 12.8p7)

    If the class definition does not explicitly declare a copy constructor, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as defaulted (8.4). The latter case is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor. Thus, for the class definition

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

    a copy constructor is implicitly-declared. If the user-declared constructor is later defined as X::X(const X& x, int i =0) { /∗ ... ∗/ } then any use of X's copy constructor is ill-formed because of the ambiguity; no diagnostic is required.

  3. If a template and non-template are an equally good match for the arguments, the non-template wins. (Standard rule 13.3.3) The rule is a big hard-to-digest mess, I'll show just the important part:

    [...] a viable function F1 is defined to be a better function than another viable function F2 if [...rules about argument matching...] or, if not that, F1 is a non-template function and F2 is a function template specialization [...]

From the code you provided, only

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

is a user-defined copy-constructor that prints 2. All X other than int don't define a copy-constructor, so the compiler creates one.

See also

Upvotes: 5

tumdum
tumdum

Reputation: 2031

It's copy constructor generated for you by compiler, and since it's best match it's selected in last case.

Upvotes: 4

Igor
Igor

Reputation: 1059

In last case you call default copy constructor.

Upvotes: 0

Related Questions