xmllmx
xmllmx

Reputation: 42297

Why can't the class inherit the member types of its parents?

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
}

Why can't the class inherit the member types of its parents?

Upvotes: 2

Views: 48

Answers (2)

songyuanyao
songyuanyao

Reputation: 172924

Because as a non-dependent name, U won't be looked up in dependent base class A<T>, which depends on template parameter T. On the other hand, for both B and C their base class are non-dependent base class.

You can change to dependent name, e.g. A<T>::U, which depends on template parameter T too. Dependent names may be looked up only at the time of instantiation, at that time the exact specialization (including base class) will be known.

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

Upvotes: 3

Brian Bi
Brian Bi

Reputation: 119164

The member U is inherited like any other member would be, irrespective of which classes are templated, but it is not found by unqualified name lookup according to C++17 [temp.dep]/3:

In the definition of a class or class template, the scope of a dependent base class (17.6.2.1) is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member.

Here, A<T> is a dependent base class since it depends on the template parameter T of the class template D.

To force the compiler to look up U in the base class, you have to use qualified name lookup. You can do it like this:

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

Another way of expressing it, if the template arguments to the base class are complicated, is:

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

If you are going to be writing this out multiple times then you could also redeclare the type in D for convenience:

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

Note: in the above contexts, typename will become optional in C++20.

Upvotes: 4

Related Questions