问题描述
我有这样的类结构.
class Interface {
// ...
};
class Foo : public Interface {
// ...
};
template <class T>
class Container {
// ...
};
我有其他类 Bar 的构造函数.
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?
推荐答案
我认为您需要的确切术语是模板协方差",这意味着如果 B 继承自 A,那么不知何故 T
继承自 T
.这不是 C++ 的情况,Java 和 C# 泛型* 也不是.
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!
}
因此,无论 A 和 B 之间的关系如何,您都应该将 T
和 T
视为完全不相关的类型.
Consequently, you should consider T<A>
and T<B>
as completely unrelated types, regardless of the relation between A and B.
那么您如何解决您面临的问题?在Java和C#中,你可以分别使用有界通配符和约束:
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 {...}
下一个 C++ 标准(称为 C++1x(以前称为 C++0x))最初包含一个更强大的机制,名为 概念,本来可以让开发人员对模板参数强制执行语法和/或语义要求,但不幸的是被推迟到以后.但是,Boost 有一个Concept Check 库,您可能会感兴趣你.
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.
尽管如此,对于您遇到的问题,概念可能有点矫枉过正,使用 @gf 可能是最好的解决方案.
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.
* 更新:从 .Net Framework 4 开始,可以将通用参数标记为 协变或逆变.
这篇关于模板多态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!