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?
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.
Templates are not polymorphic. Templates are bound at compile-time, unlike polymorphic objects which are bound at run-time.
Overloaded functions and templates provide static (compile-time) polymorphism.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With