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)