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);
}
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