如何在 C++ 中使用模板类型的子类传递模板函数参数?
Posted
技术标签:
【中文标题】如何在 C++ 中使用模板类型的子类传递模板函数参数?【英文标题】:How to pass a templated function parameter with a subclass of the templated type in C++? 【发布时间】:2020-05-31 22:14:37 【问题描述】:编译以下人为的例子:
class Base
;
class Derived : public Base
;
template< typename T >
class A
;
class B
public:
static void f( const A< Base >& )
;
int main()
A< Base > tb;
A< Derived > td;
B::f( tb );
B::f( td );
return 0;
使用 g++-8 会出现以下错误:
error: no matching function for call to 'B::f(A<Derived>&)'
B::f( td );
note: no known conversion for argument 1 from 'A<Derived>' to 'const A<Base>&'
为什么?
既然Derived
is-a Base
并且它不会覆盖任何Base
的东西,为什么我不能用Derived
代替a Base
在模板化函数参数中?
【问题讨论】:
A< Base >
和 A< Derived >
是不同的、不相关的类。他们之间没有转换。它们之间根本不必有任何相似之处——它们可以有完全不同的成员。
【参考方案1】:
Derived
确实是从 Base
派生的,但这并不意味着 A<Derived>
因此必须从 A<Base>
派生。 C++ 模板不能以这种方式工作。
A<Derived>
是一个类,由A
模板实例化。你可以简单地声明:
class A_Derived
// ...
;
使用相同的成员(如果有的话),并且几乎得到相同的结果。 A<Base>
也一样。图片中没有其他内容,这两个班级绝对没有任何关系。你可以在这里画一个心理图,好像你做了以下声明:
class A_Derived
;
和
class A_Base
;
这几乎就是历史。您是否看到 A_Derived
明确派生自 A_Base
这里?显然不是。如果某些东西需要一个引用或指向A_Base
的指针,你不能给它A_Derived
,因为这两个类彼此完全没有关系。它们是独立的类。
附:如果您愿意,可以将 A<Derived>
的显式特化声明为派生自 A<Base>
,但特化是完全不同的主题...
【讨论】:
【参考方案2】:模板实例,如A<Base>
和A<Derived>
,是不同的类型。特别是即使Base
和Derived
有继承关系,它们也没有任何继承关系。
有很多方法可以让你想要的东西发挥作用。
首先,您可以使 A<Derived>
显式派生自 A<Base>
,但这意味着添加整个类定义。
template<>
class A<Derived> : public A<Base>
;
其次,您可以通过构造函数模板的形式提供从A<Derived>
到A<Base>
的隐式转换。您可以使用std::enable_if
和std::is_base_of
仅允许A<T>
其中T
派生自Base
,或者如果您只想考虑这个特定的Derived
类型,则直接使用std::is_same
。
template<typename T>
class A
template<typename U, typename = std::enable_if_t<std::is_base_of_v<T, U>>>
A(A<U> const& other);
;
第三,您可以以运算符模板的形式提供隐式转换,方式大致相同。
template<typename T>
class A
template<typename U, typename = std::enable_if_t<std::is_base_of_v<U, T>>>
operator U();
;
第四,你可以把f
做成一个函数模板,并限制它需要什么类型。
template<typename T, typename = std::enable_if_t<std::is_base_of_v<Base, T>>>
static void f(A<T> const& a);
【讨论】:
以上是关于如何在 C++ 中使用模板类型的子类传递模板函数参数?的主要内容,如果未能解决你的问题,请参考以下文章