【问题标题】:How to pass a templated function parameter with a subclass of the templated type in C++?如何在 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&lt; Base &gt;A&lt; Derived &gt; 是不同的、不相关的类。他们之间没有转换。它们之间根本不必有任何相似之处——它们可以有完全不同的成员。

标签: c++ templates inheritance


【解决方案1】:

Derived 确实是从 Base 派生的,但这并不意味着 A&lt;Derived&gt; 因此必须从 A&lt;Base&gt; 派生。 C++ 模板不能以这种方式工作。

A&lt;Derived&gt; 是一个类,由A 模板实例化。你可以简单地声明:

class A_Derived {

     // ...

};

使用相同的成员(如果有的话),并且几乎得到相同的结果。 A&lt;Base&gt; 也一样。图片中没有其他内容,这两个班级绝对没有任何关系。你可以在这里画一个心理图,好像你做了以下声明:

class A_Derived {

};

class A_Base {

};

这几乎就是历史。您是否看到 A_Derived 明确派生自 A_Base 这里?显然不是。如果某些东西需要一个引用或指向A_Base 的指针,你不能给它A_Derived,因为这两个类彼此完全没有关系。它们是独立的类。

附:如果您愿意,可以将 A&lt;Derived&gt; 的显式特化声明为派生自 A&lt;Base&gt;,但特化是完全不同的主题...

【讨论】:

    【解决方案2】:

    模板实例,如A&lt;Base&gt;A&lt;Derived&gt;,是不同的类型。特别是即使BaseDerived 有继承关系,它们也没有任何继承关系。

    有很多方法可以让你想要的东西发挥作用。

    首先,您可以使 A&lt;Derived&gt; 显式派生自 A&lt;Base&gt;,但这意味着添加整个类定义。

    template<>
    class A<Derived> : public A<Base>
    {};
    

    其次,您可以通过构造函数模板的形式提供从A&lt;Derived&gt;A&lt;Base&gt; 的隐式转换。您可以使用std::enable_ifstd::is_base_of 仅允许A&lt;T&gt; 其中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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-04-24
      • 1970-01-01
      • 2015-07-29
      • 2011-04-04
      • 2011-03-31
      • 2011-10-13
      • 1970-01-01
      相关资源
      最近更新 更多