Я думаю, что точная терминология для того, что вам нужно, это "ковариация шаблона", означающая, что если B наследуется от A, то каким-то образом T<B>
наследуется от T<A>
. Это не так в C ++, а также в случае Java и C # generics *.
Есть веская причина избегать ковариации шаблона: это просто удалит все типы безопасности в классе шаблона. Позвольте мне объяснить на следующем примере:
//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!
}
Следовательно, вы должны рассматривать T<A>
и T<B>
как совершенно не связанные типы, независимо от отношения между A и B.
Так как вы могли решить проблему, с которой вы столкнулись? В Java и C # можно использовать соответственно ограниченные подстановочные знаки и ограничения :
//Java code
Bar(Container<? extends Interface) {...}
//C# code
Bar<T>(Container<T> container) where T : Interface {...}
Следующий стандарт C ++ (известный как C ++ 1x (ранее C ++ 0x)) изначально содержал еще более мощный механизм с именем Concepts , который позволил бы разработчикам обеспечивать соблюдение синтаксических и / или семантических требований. по параметрам шаблона, но, к сожалению, был отложен на более поздний срок. Однако в Boost есть библиотека Concept Check , которая может вас заинтересовать.
Тем не менее, концепции могут быть немного излишними для проблемы, с которой вы сталкиваетесь, использование простого статического утверждения, предложенного @ gf , вероятно, является лучшим решением.
* Обновление: начиная с .Net Framework 4, можно отметить, что общие параметры имеют ковариантный или контравариантный .