0

I'm trying to use a type member of a class in its child, but I'm failing. In particular, I can't understand why this code does not compile:

template <typename T>
class A {
    public:
        using t = T;
        
        A() {}
};

template <typename T>
class B: public A<T> {
    public:
        B() : A<T>() {}
        
        A<T>::t foo(A<T>::t x) {
            return x;
        }
};

I've also tried A::t and B::t but none of them is working. Maybe I'm missing something on how to access inherited type members. Compiler Error:

error: need ‘typename’ before ‘A<T>::t’ because ‘A<T>’ is a dependent scope
   A<T>::t foo(A<T>::t x) {

PS: I know that I could use simply T instead of trying to access A::t in this particular case, but the question is still valid.

L.A.
  • 243
  • 2
  • 12
  • please include the compiler error message in the question – 463035818_is_not_an_ai Jun 24 '21 at 20:38
  • 2
    fun fact: gccs error message tells you exactly how to fix it https://godbolt.org/z/Wh4r513bn. iirc there is a proposal to lift the requirement for `typename` when there is no ambiguity, until then we still have to put it just because the standard says so – 463035818_is_not_an_ai Jun 24 '21 at 20:41

1 Answers1

4

Since A<T>::t depends on a template parameter, it requires a typename:

typename A<T>::t foo(typename A<T>::t x)

Because it depends on a template parameter, it must always be qualified (i.e. have :: to the left of it), so just the plain t wouldn't work.

typename B::t would also work.

typename A::t wouldn't work because injected-class-name A itself (i.e. the shorthand version that doesn't require template arguments) also depends on a template parameter. You could do typename B::A::t, but it's superfluous.


If you put this in your class: using typename A<T>::t;

Then you'll be able to use t as is. Notably, using typename B::t; doesn't work.


If the base class didn't depend on a template parameter (e.g. template <typename T> class B : public A<int>), then typename wouldn't be necessary.

In that case, all of the following would work: t, B::t, A::t, B::A::t, optionally with the template arguments for A and/or B specified.

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
  • What is the difference between the 2 possibilities? Why does the B version require the typename even no template needs to be specified? – L.A. Jun 24 '21 at 20:41
  • @L.A. There is no difference. `B` acts a shorthand for `B`, so it too depends on a template parameter. – HolyBlackCat Jun 24 '21 at 20:42
  • Related: [Where and why do I have to put the “template” and “typename” keywords?](https://stackoverflow.com/questions/610245/) – Remy Lebeau Jun 24 '21 at 20:55