Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Templates polymorphism

I have this structure of classes.

class Interface {   // ... };  class Foo : public Interface {   // ... };  template <class T> class Container {   // ... }; 

And I have this constructor of some other class Bar.

Bar(const Container<Interface> & bar){   // ... } 

When I call the constructor this way I get a "no matching function" error.

Container<Foo> container ();  Bar * temp = new Bar(container); 

What is wrong? Are templates not polymorphic?

like image 393
Rusty Horse Avatar asked Feb 04 '10 21:02

Rusty Horse


People also ask

What are templates in polymorphism?

Compile-time polymorphism is provided by templates in C++. A template function or class can take any type which conforms to a prototype, usually called a "concept". Unlike base classes and virtual functions, the prototype is implicit: the prototype is defined only by how the type is used by the template function/class.

Are C++ templates polymorphism?

Templates are not polymorphic. Templates are bound at compile-time, unlike polymorphic objects which are bound at run-time.

Are templates static polymorphism?

Overloaded functions and templates provide static (compile-time) polymorphism.

Is runtime a polymorphism template?

Run-time polymorphism is based on object orientation and virtual functions in C++, compile-time polymorphism is based on templates. Both polymorphisms have pros and cons that I discuss in the following post.


1 Answers

I think the exact terminology for what you need is "template covariance", meaning that if B inherits from A, then somehow T<B> inherits from T<A>. This is not the case in C++, nor it is with Java and C# generics*.

There is a good reason to avoid template covariance: this will simply remove all type safety in the template class. Let me explain with the following example:

//Assume the following class hierarchy class Fruit {...};  class Apple : public Fruit {...};  class Orange : public Fruit {...};  //Now I will use these types to instantiate a class template, namely std::vector int main() {     std::vector<Apple> apple_vec;     apple_vec.push_back(Apple()); //no problem here      //If templates were covariant, the following would be legal     std::vector<Fruit> & fruit_vec = apple_vec;      //push_back would expect a Fruit, so I could pass it an Orange     fruit_vec.push_back(Orange());       //Oh no! I just added an orange in my apple basket! } 

Consequently, you should consider T<A> and T<B> as completely unrelated types, regardless of the relation between A and B.

So how could you solve the issue you're facing? In Java and C#, you could use respectively bounded wildcards and constraints:

//Java code Bar(Container<? extends Interface) {...}  //C# code Bar<T>(Container<T> container) where T : Interface {...} 

The next C++ Standard (known as C++1x (formerly C++0x)) initially contained an even more powerful mechanism named Concepts, that would have let developers enforce syntaxic and/or semantic requirements on template parameters, but was unfortunately postponed to a later date. However, Boost has a Concept Check library that may interest you.

Nevertheless, concepts might be a little overkill for the problem you encounter, an using a simple static assert as proposed by @gf is probably the best solution.

* Update: Since .Net Framework 4, it is possible to mark generic parameters has being covariant or contravariant.

like image 82
Luc Touraille Avatar answered Sep 30 '22 20:09

Luc Touraille