MaPo
MaPo

Reputation: 855

Different behavior between g++ and clang++ in nested classes

I noticed a different behavior between gcc 9.2.0 and clang++ 9.0.1. My code is as follows

//header.hh
     ...
template <typename T>
class Outer {
     ...
  public:
     template <typename S>
     class Inner;
     ... 
};

template <typename T>
template <typename S>
class Inner {
     ...
      Inner& func();
     ...
};

then, since the function func() is implemented in another file

//implementation.cc
template <typename T>
template <typename S>
Outer<T>::Inner<S>& Outer<T>::Inner<S>::func() {
    ...
};

Now, if I use g++ the compilation is OK. If I use clang++ I get

src/implementation.cc:6:1: error: missing 'typename' prior to dependent type template name 'Outer<T>::Inner'
Outer<T>::Inner<S>& Outer<T>::Inner<S>::func() {
^
1 error generated.

However if I follow its suggestion and use

typename Outer<T>::Inner<S>& Outer<T>::Inner<S>::func()

I got another error:

src/implementation.cc:6:21: error: use 'template' keyword to treat 'Inner' as
a dependent template name typename Outer<T>::Inner<S>& Outer<T>
::Inner<S>::func() {

And now its suggestion seems very weird.

QUESTIONS

  1. Why the two compiler are behaving differently?
  2. What is the correct syntax to use?

Upvotes: 0

Views: 122

Answers (1)

r3mus n0x
r3mus n0x

Reputation: 6144

The correct syntax would be the following:

template <typename T>
template <typename S>
typename Outer<T>::template Inner<S> &Outer<T>::Inner<S>::func() {
    ...
}

You can find the full explanation for this syntax in this question.

However, a simpler and also valid syntax would be this:

template <typename T>
template <typename S>
auto Outer<T>::Inner<S>::func() -> Inner& {
    ...
}

By using the trailing return type syntax in the example above you can take advantage of the fact that the name resolution scope is within Outer<T>::Inner<S> at that point so you can use the injected class name of the Inner.

Upvotes: 1

Related Questions