1

The print statement in the constructor's definition doesn't get printed, isn't the constructor calling correct in main? I know I am missing some point here, please point out.

#include <iostream>
#include <typeinfo>

template <typename T> class List
{
    public: 
        template <typename T2> List (List<T2> const&);
}; 

template <typename T> template <typename T2> List <T> :: List (List <T2> const&) 
{
    std :: cout << "\nType name:" << typeid (T2).name();
}

int main ()
{
    List <int> kk (List <int>);
    return 0;
}
AProgrammer
  • 51,233
  • 8
  • 91
  • 143
Aquarius_Girl
  • 21,790
  • 65
  • 230
  • 411

3 Answers3

6

There are a couple of things wrong in your code that you might not be aware of.

List<int> kk( List<int> );

That line is not a variable definition, but rather the declaration of a function that takes a List<int> as argument and returns a List<int>, so that effectively will not call any constructor. That is know as the most-vexing-parse (you can look at different versions of it by searching in SO, or in the C++ FAQ lite)

The second issue is that you cannot possibly create any instance of the an instantiated type of List, the reason being is that the only constructor that you are providing is a templated constructor that takes a second List<U> as argument. That effectively disables the default constructor, so the only way of creating a List<T> is by already having a List<U>, and that is not possible. You can add the default constructor back:

template <typename T>
class List {
public:
   List() {}
   template <typename U>
   List( List<U> const & ) {} // prefer const& as that will avoid unnecessary copying
};

And now you can write:

List<int> l = List<int>(); // this will call List<int>::List( List<int> const & )

And yet, that will still not call the constructor you want. The reason is a little obscure, but when copy constructing an element of a template, the compiler will not use a templated constructor. In the code above, it will implicitly define a copy constructor by doing member-wise copy constructor of the methods and call that generated constructor. That means that in most occasions where you want to provide a templated constructor you want to also provide a non-templated copy constructor.

To actually call that constructor you would have to provide a different type:

List<int> l = List<double>();

Since the types actually differ, the compiler cannot copy construct, will find that the provided templated constructor is the best overload candidate and call it.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • Thanks, but what is an SO? I often see people referring to that. – Aquarius_Girl Apr 20 '11 at 07:24
  • @AProgrammer Sorry but I don't understand, the tag "most-vexing-parse" tag doesn't give me any threads or you meant something else? – Aquarius_Girl Apr 20 '11 at 07:31
  • @Anisha Kaul: Enter "[most-vexing-parse]" without the quotes in the search box, or google for "most vexing parse C++"... – David Rodríguez - dribeas Apr 20 '11 at 07:33
  • @anisha, click on the tag I've added to your question, you'll find out similarly tagged one. -- That's possible for any tags. – AProgrammer Apr 20 '11 at 07:36
  • @AProgrammer I did click on _that_ tag but it results in nothing – Aquarius_Girl Apr 20 '11 at 07:56
  • @David First of all let me explain my reasons of writing this: `List kk( List ); `If I would have written `List kk` this would mean that kk is an object of the class List (that would have called the default constructor). But the constructor in question takes a template parameter which I showed by `kk (List )` I'll go through the link you posted. – Aquarius_Girl Apr 20 '11 at 08:14
  • @David In your second paragraph, did you mean that because the parametrized constructor is taking an argument _the object of class List_ thereofre it is not possible to create any object of it? – Aquarius_Girl Apr 20 '11 at 08:25
  • @David `List kk;` gave me a compilation error, tried just now, thanks a lot. – Aquarius_Girl Apr 20 '11 at 08:31
  • @David and finally I searched "SO" with the most-vexing-parse keyword and got this: "http://stackoverflow.com/questions/1424510/most-vexing-parse-why-doesnt-a-a-work" It was very helpful, thanks again. – Aquarius_Girl Apr 20 '11 at 08:49
  • @David I said in my previous comments that I have understood your point. thanks again for the wonderful explanation. – Aquarius_Girl Apr 20 '11 at 09:22
2

As well as the "most vexing parse" identified by David:

  • you need to have at least one more constructor to create the original List object to be passed to the copy constructor,
  • you need to vary the parameter type in order to have the templated copy constructor invoked: as is you'll match the implicitly declared List(const List&) copy constructor instead.

So:

#include <iostream>

template <typename T>
struct X
{
    X() { std::cout << "X()\n"; }

    // implicitly like this anyway...
    // X(const X& rhs) { std::cout << "X(X&)\n"; }

    template <typename U>
    X(const U& u) { std::cout << "U\n"; }
};

int main()
{
    X<int> x;
    X<int> y(x);
}
Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
1

What are you trying to do with this statement:

List <int> kk (List <int>);

(It actually declares a function, and can't be anything but a function declaration.)

In order to see output from the copy constructor, you've got to invoke the copy constructor somehow. Which means having an object to copy. Which isn't possible with the code you've given: since you've explicitly declared a constructor, the compiler will not provide a default constructor, and you have no other constructor with which to create an object. So you have no way of creating anything to copy. If you add a

List() {}

to the class, and write:

List<int> kk((List<int>());

, you might get something, but the compiler is allowed to elide the copy here, so more likely there will be no output. Try:

List<int> a;
List<int> b(a);

Or just put your output in the default constructor.

James Kanze
  • 150,581
  • 18
  • 184
  • 329