Is this absurd code that compiles minor bugs in both Clang and GCC?

Today I played with templates to find out if I can get the compiler to infer the type of an outer class from one of its inner classes. I did not find my solution (which, I suspect, is impossible), but trying to fix the error, I came across a very strange behavior, which I changed to the next fragment.

struct A { struct B{}; template <typename T> struct EverythingIsFine { using Outer = T; using Inner = typename T::B::B::B::B::B::B; }; using ItWillBeOkay = EverythingIsFine<B>; // Probably not ok using InnerProblem = ItWillBeOkay::Inner; // Still not ok using OuterProblem = decltype(B().ItWillBeOkay::Outer::B::B::B ::B::B::B::~B()); // Not even CLOSE to ok }; 

This compiles surprisingly without warning or error with Clang and GCC.
The modifiers of my compilers are gcc version 5.3.1 20160121 (Debian 5.3.1-7) and Debian clang version 3.6.2-3 (tags/RELEASE_362/final) (based on LLVM 3.6.2) , and the flag used to compile, is -std=c++11 -Wall -Wextra .

I noticed that it also compiles Fine in Ideone with a C ++ 14 setup .


Then I used this simple test to get the exact types of InnerProblem and OuterProblem :

 template <class T> void Type(); int main() { Type<A::InnerProblem>(); Type<A::OuterProblem>(); } 

And both compilers report the same types when compiling the test:

In the main function:
main.cpp: 20: undefined reference to void Type<A::B>()
main.cpp: 21: undefined reference to void Type<void>()

That is, the InnerProblem type is A::B , and the OuterProblem type is void .


Is this somehow permitted by the standard or is it a mistake in both compilers?
And since I seem to be just as confused as my compiler, what actually happens with this code?

EDIT . As a simplified follow-up, since I don’t understand why the two compilers cannot give the same result, the following code is compiled with Clang, but not with GCC.

 struct A { struct B{}; template <typename T> struct EverythingIsFine { using Inner = typename T::B::B::B; }; using Problem = EverythingIsFine<B>::Inner::B::B::B; // Not ok }; 

GCC now displays the following error:

main.cpp: 11: 26: error: "A :: B :: B" calls the constructor, not the type using InnerProblem = EverythingIsFine :: Inner :: B :: B :: B; // Do not like it

+8
c ++ language-lawyer c ++ 11 g ++ clang
source share
1 answer

It's really.

The class name is also inserted into the scope of the class itself; this is known as the name of the introduced class. "(9/2).

So B::B names the class B , like B::B::B , etc.

EDIT:

So, typename B::B names the class B , like typename B::B::B , etc.

+6
source share

All Articles