Почему класс не может наследовать типы членов своих родителей? - PullRequest
2 голосов
/ 30 апреля 2020
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
}

Почему класс не может наследовать типы членов своих родителей?

Ответы [ 2 ]

4 голосов
/ 30 апреля 2020

Член 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.

3 голосов
/ 30 апреля 2020

Поскольку как независимое имя, U не будет найдено в зависимом базовом классе A<T>, который зависит от параметра шаблона T. С другой стороны, для B и C их базовый класс является независимым базовым классом.

Можно изменить на зависимое имя, например, A<T>::U, что зависит от параметра шаблона T тоже. Зависимые имена можно искать только во время создания экземпляра, тогда точная специализация (включая базовый класс) будет известна.

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