On Sun, Dec 7, 2025 at 7:56 AM Andrey Tarasevich via Gcc <[email protected]> wrote: > > I'm curious about the following specific context: referring to a member type > (supposedly, an injected class name) through a dependent type name with a > `typename` keyword > > struct S {}; > > template <typename T> void foo() { > typename T::S s; // <-- this > } > > int main() { > foo<S>(); > } > > GCC quietly accepts the declaration inside `foo` (even with `-pedantic`), i.e. > it treats `T::S` as a reference to the injected class name. Clang issues the > following diagnostic > > warning: ISO C++ specifies that qualified reference to 'S' is a constructor > name rather than a type in this context, despite preceding 'typename' > keyword > [-Winjected-class-name] > > which expectedly turns into an error in `-pedantic-errors` mode. > > Is Clang correct in this case? (Considering how elaborate and specific its > message is.) > > Note that the dilemma arises only when the actual argument is a type named > `S`. > If a differently named type is passed as `T` (which just happens to have `S` > as > a member type), both compilers accept the code (see the example below). This > distinction is what tempted me to test this context in the first place, and > what > leads me to believe that Clang's behavior is "weird" (even if correct). > > The difference can be converted to something more tangible by exploiting it > for > SFINAE purposes, e.g. > > #include <iostream> > > struct A { using B = int; }; > struct B {}; > struct C {}; > > template <typename T> void foo(int, typename T::B * = 0) { > std::cout << "Hello World" << std::endl; > } > > template <typename T> void foo(...) { > std::cout << "Goodbye World" << std::endl; > } > > int main() { > foo<A>(0); > foo<B>(0); // GCC vs Clang? > foo<C>(0); > }
I don't know but here is a summary of the compilers I tried: GCC: 2 hello worlds clang: 2 goodbye worlds EDG: 2 goodbye worlds MSVC: 2 hello worlds. There are a few C++ defect reports in this area even. https://cplusplus.github.io/CWG/issues/1310.html and https://cplusplus.github.io/CWG/issues/318.html >From my understanding (but I could still be wrong), GCC and MSVC are correct. because typename should cause the "function names" to be ignored (a nested-name-specifier). The reason why I could be wrong is clang marks as implementing DR 1310 while GCC marks as unknown if it implements DR 1310. There could be still another reason why the injected name is the naming the constructor that I don't understand either. Thanks, Andrew Pinski > > In GCC this program outputs > > Hello World > Hello World > Goodbye World > > (https://godbolt.org/z/rjGhjzo8q). > > And in Clang it outputs > > Hello World > Goodbye World > Goodbye World > > (https://godbolt.org/z/PejjP6h6K) > > -- > Best regards, > Andrey
