Template class pointer c++ declaration

2020-05-16 02:36发布

问题:

template <typename T>
class Node
{...};

int main
{
    Node* ptr;
    ptr = new Node<int>;
}

Will fail to compile I have to to declare the pointer as

Node<int>* ptr;

Why do I have to specify the type when declaring a pointer I haven't created the class yet, why does the compiler have to know what type it will be pointing to. And is it not possible to create a generic pointer and decide afterwards what type I want to assign it.

回答1:

Templating resolves types at compile-time. When you assign the new Node<int> object to it, the pointer must know at compile-time what type exactly it is.

Node<int> and Node<std::vector> can be very different in the binaries (the binary layout of your object changes completely according the template parameter) so it doesn't make any sense to have an unresolved pointer type to a template.

You should define first a common parent class for your nodes:

class NodeBase
{ ... }

template<typename ValueT>
  class Node : public NodeBase
{
 ...
};

NodeBase* ptr;


回答2:

The simple answer is because C++ uses (fairly) strict static type checking. Node<int> is a completely unrelated type to Node<double>, and when the compiler sees ptr->doSomething(), it has to know whether to call Node<int>::doSomething() or Node<double>::doSomething().

If you do need some sort of dynamic generality, where the actual type ptr will point to will only be known at runtime, you need to define a base class, and derive from that. (It's a fairly common idiom for a class template to derive from a non-template base, precisely so that the generality in the pointers can be resolved at runtime.)



回答3:

Why do I have to specify the type when declaring a pointer I haven't created the class yet, why does the compiler have to know what type it will be pointing to.

There are lots of things you're allowed to do with a pointer, just to list a very few:

  • call one of many functions based on the pointer's type
  • index from it (on the assumption that it points to the first elements in a contiguous array of such objects)
  • take the size of the pointed-to object
  • pass it to a template where the pointer-type is a parameter

For the compiler to generate code to do these efficiently, it needs to know the type of the pointer. If it defered the decisions until it saw the type of the pointer, then it would need to either:

  • compile efficient code for every possible type the pointer might later take (making a hugely bloated program), or
  • create inefficient code that can handle all the possible types through some worst-case pessimistic clumsy behaviours, or
  • embed a copy of itself (the compiler) into your C++ program so it can complete it's job when it's got the necessary information - that would make every trivial program huge (and slow)

And is it not possible to create a generic pointer and decide afterwards what type I want to assign it.

Kind of... you have many options:

  • use a void*, but before it can meaningfully operate on the pointed-to-type again you'll need to manually cast it back to that type: in your case that means recording somewhere what it was then having separate code for every possibility
  • use boost::any<> - pretty much like a void*, but with safety built in
  • use boost::variant<> - much safer and more convenient, but you have to list the possible pointed-to types when you create the pointer
  • use a runtime polymorphic family of objects and virtual dispatch... this is classic Object Oriented Programming... you have a pointer to an "abstract" Node that declares the shared functions and member data you'd use to operate on any particular type of node, then the templated Node class derives from that abstract Node and implements type-specific versions of the functions. These are then called via a pointer to the base class using virtual functions.


回答4:

Whenever you create any kind of object (including pointers) in C++, the full type of the object must be known. There is no such type in your code as Node, so you can't create instances of pointers to it. You need to rethink how you are designing and writing your code.



回答5:

As both Neil Butterworth and Luc Danton noted, you can't have a pointer of type Node* because Node is not a type. It is a template. Yes, Node is a class template, but that class here just qualifies the kind of template. One way to look at it: Just as classes and instances of classes are very different things, so too are templates and template instantiations. It is those template instantiations such as Node that are classes. The class template is some other kind of beast.