I found that the code snippet below compiles fine on gcc 11, clang, and MSVC, but starting with gcc 12.1, it gives the error:

using Y = typename Derived::template X<1>;  // offending line

error: 'class Derived<T>::X<1>' resolves to 'Base<double>::X<1>' {aka 'double'}, which is not a class type

Why does the alias need to resolve to a class type for this to be a properly formed alias?

Minimal Example Code (godbolt):

#include <iostream>

template <typename T>
struct Base {
  template <int I>
  using X = T;
};

template <typename T>
struct Derived : public Base<T> {
  using Y = typename Derived::template X<1>;
};

struct O {};

int main() {
  std::cout << typeid(Derived<double>::Y).name() << std::endl;  // error
  std::cout << typeid(Derived<O>::Y).name() << std::endl;       // works
}

In the code in question, I'm trying to create an alias to a parent's (templated) alias, but it only works when the alias resolves to a class type. Of course, something like using Y = double; is perfectly legal, and when any of Base, Derived, or X are not templated it also seems to work fine, so how come this particular combination of dependent types makes it so that X<something> is no longer allowed to resolve to e.g. arithmetic types, and only on gcc 12.1 and up?

I skimmed through the gcc 12 change list but didn't see anything that struck out to me as related.

(I'm using c++11 but it that doesn't seem to be relevant as it also occurs when specifying c++14, 17, 0x)

0

There are 0 answers