开发者

Finding typeid of a template parameter

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;
}


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.


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);
}


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜