0

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?
r3mus n0x
  • 5,400
  • 1
  • 8
  • 30
MaPo
  • 275
  • 2
  • 6
  • 3
    You have a bigger problem to worry about. Even after you square the compilation error, despite the limited information given your question it seems very likely that your program will fail to link, by either compiler, because templates can only be implemented in header files. Your attempt to define the template in something called "implementation.cc" is doomed to an utter and complete failure. C++ simply does not work this way. – Sam Varshavchik Feb 09 '20 at 17:08
  • Could you please update your examples, they are inconsistent with error messages (e.g. Inner-Outer order, Iterator class). – r3mus n0x Feb 09 '20 at 17:10
  • That too, you need to [edit] your question to contain only one code snippet that demonstrates the compilation error you're asking about. – Sam Varshavchik Feb 09 '20 at 17:15
  • I edited the question. However I'm very sorry for my ignorance. I simply did not know that one cannot separate definition of a template from the declaration. – MaPo Feb 09 '20 at 17:19
  • Your question still is short of a [mre]. Can you cut/paste what you have in your question, and reproduce your compilation error? Obviously not, and until it is, it's not a [mre] by definition. The best way to get this kind of help is to make it as easy as possible for everyone else to reproduce your error. – Sam Varshavchik Feb 09 '20 at 17:23

1 Answers1

1

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.

r3mus n0x
  • 5,400
  • 1
  • 8
  • 30