代码之家  ›  专栏  ›  技术社区  ›  xmllmx

为什么模板类不能继承其父类的成员类型?

  •  0
  • xmllmx  · 技术社区  · 5 年前
    template<typename T>
    struct A
    {
        using U = int;
    };
    
    struct B : A<int>
    {
        void f(U) // ok
        {}
    };
    
    template<typename T>
    struct C : A<int>
    {
        void f(U) // ok
        {}
    };
    
    template<typename T>
    struct D : A<T>
    {
        void f(U) // fatal error: unknown type name 'U'
        {}
    };
    
    int main()
    {
        B      b; // ok
        C<int> c; // ok
        D<int> d; // error
    }
    

    为什么类不能继承其父类的成员类型?

    0 回复  |  直到 5 年前
        1
  •  4
  •   Brian Bi    5 年前

    成员 U 与任何其他成员一样被继承,无论模板化了哪些类,但根据C++17[temp.dep]/3,通过非限定名称查找找不到它:

    在类或类模板的定义中,在类模板或成员的定义点或实例化过程中,在非限定名称查找期间不会检查依赖基类(17.6.2.1)的范围。

    在这里, A<T> 是一个依赖基类,因为它依赖于模板参数 T 类模板的 D .

    强制编译器查找 U 在基类中,必须使用限定名查找。你可以这样做:

    void f(typename A<T>::U);
    

    如果基类的模板参数很复杂,另一种表达方式是:

    void f(typename D::A::U);
    

    如果你要多次写出来,那么你也可以在中重新声明该类型 D 为方便起见:

    using U = typename A<T>::U;
    void f(U);
    

    注:在上述情况下, typename 将在C++20中变为可选。

        2
  •  3
  •   songyuanyao    5 年前

    因为作为非依赖名称, U 不会在依赖基类中查找 A<T> ,这取决于模板参数 T 另一方面,对于两者 B C 它们的基类是非依赖基类。

    您可以更改为从属名称,例如。 A<T>::U ,这取决于模板参数 T 我也是。只能在实例化时查找依赖名称,届时将知道确切的专门化(包括基类)。

    template<typename T>
    struct D : A<T>
    {
        void f(typename A<T>::U)
        {}
    };