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