Inner template classes inheritance

Viewed 416

I have the following code: https://gist.github.com/PatrikValkovic/50329975f86e0328ff1f85fda17a23f3, live example here: http://cpp.sh/675a3.

In short, I have class A with inner class B<U> and class D that should inherit from the B<U>. The code works when the class D is declared within class A (as commented). However, when I move the declaration outside of the class A (as in the example), the compiler complains, that A<T>::B<U> is not a type. What is wrong about the syntax?

// Example program
#include <iostream>
#include <string>

using namespace std;

template<typename T>
class A
{
public:
    template<typename U>
    class B;    

    /*
    class D : public B<int>
    {
    public:
        void method2() {
            cout << "Method 2" << endl;
            this->method1();
        }
    };
    */

    class D;
};

template<typename T>
template<typename U>
class A<T>::B 
{
public:
    void method1() {
        T x;
        cout << "Method 1: " << x << endl;
    }
};

template<typename T>
class A<T>::D : public A<T>::B<int>
{
public:
    void method2() {
        cout << "Method 2" << endl;
        this->method1();
    }
};

int main()
{
  A<int>::D b;
  b.method2();
}
1 Answers

This is one of those really weird edge cases in the C++ language that has a unusual fix. The issue is here:

template<typename T>
class A<T>::D : public A<T>::B<int>
                       ^^^^^^^^^^^^

The problem is that you are trying to use the template class B, which is a dependent name inside of A (that is, B is a template nested inside another type that depends on a template argument, here, T). By default, C++ won't treat dependent names as being names of types or names of templates, and you have to explicitly tell the compiler "yes, this is the name of a template" by using the template keyword in an unusual way:

template<typename T>
class A<T>::D : public A<T>::template B<int>
                             ^^^^^^^^

This tells C++ "inside of A<T>, you're going to find a template type named B. Please use that template with argument int."

This is similar to how you have to use the typename keyword with dependent types - it tells the compiler "yes, this is the name of a type." Here, the template keyword tells the compiler "yes, this is the name of a template."

Related