I like to use local classes in template classes to execute constructs such as "static if". But I ran into a problem that gcc 4.8 does not want to compile my code. However 4.7 does.
This example:
#include <type_traits> #include <iostream> #include <string> using namespace std; struct A { void printA() { cout << "I am A" << endl; } }; struct B { void printB() { cout << "I am B" << endl; } }; template <typename T> struct Test { void print() { struct IfA { constexpr IfA(T &value) : value(value) { } T &value; void print() { value.printA(); } }; struct IfB { constexpr IfB(T &value) : value(value) { } T &value; void print() { value.printB(); } }; struct Else { constexpr Else(...) {} void print() { } }; typename conditional<is_same<T, A>::value, IfA, Else>::type(value).print(); typename conditional<is_same<T, B>::value, IfB, Else>::type(value).print(); } T value; }; int main() { Test<A>().print(); Test<B>().print(); }
Options:
g++ --std=c++11 main.cc -o local-sfinae
Task:
- For classes A and B with different print interfaces. A.
- Write a general class test that can print both A and B.
- Contaminate neither the namespace nor the content area.
Code Description:
- This is just a pure example.
- I use this approach because I want to generalize the construction of "static if". See That I pass arguments to the IfA and IfB classes through their fields, and not directly to the print () function.
- I use such designs a lot.
- I found that these constructions should not be in the (polluting) class. I mean, they should be placed in the scope of the method.
So the question is.
This code cannot be compiled with GCC 4.8. Because it checks ALL classes, even if they are never used. But it does not create them in binary format (I commented out the lines that cause errors, and compiled them with gcc 4.8). Evidence:
$ nm local-sfinae |c++filt |grep "::If.*print" 0000000000400724 W Test<A>::print()::IfA::print() 00000000004007fe W Test<B>::print()::IfB::print()
Look, there is no test :: print () :: IfB :: print (). (See Below: 'void Test :: print () :: IfB :: print () [with T = A]')
Errors if I compile the above code with gcc 4.8:
g++ --std=c++11 main.cc -o local-sfinae main.cc: In instantiation of 'void Test<T>::print()::IfB::print() [with T = A]': main.cc:36:9: required from 'void Test<T>::print() [with T = A]' main.cc:49:21: required from here main.cc:34:17: error: 'struct A' has no member named 'printB' value.printB(); ^ main.cc: In instantiation of 'void Test<T>::print()::IfA::print() [with T = B]': main.cc:28:9: required from 'void Test<T>::print() [with T = B]' main.cc:50:21: required from here main.cc:26:17: error: 'struct B' has no member named 'printA' value.printA(); ^
- Is this a GCC 4.8 bug?
- Or is it a GCC 4.7 bug? Perhaps the code should not compile.
- Or this is my mistake, and I should not rely on the behavior of the compiler / should not use this approach to implement "static if".
Additional Information:
This simple code compiles on 4.7, but not 4.8. I cut it.
struct A { void exist() { } }; template <typename T> struct Test { void print() { struct LocalClass { constexpr LocalClass(T &value) : value(value) { } T &value; void print() { value.notExist(); } }; } T value; }; int main() { Test<A>().print(); }
Errors:
main.cc: In instantiation of 'void Test<T>::print()::LocalClass::print() [with T = A]': main.cc:16:9: required from 'void Test<T>::print() [with T = A]' main.cc:22:21: required from here main.cc:14:17: error: 'struct A' has no member named 'notExist' value.notExist(); ^
We tested two versions of GCC 4.8: 2012.10 and 2013.02. Hope this is GCC 4.8 error and it can be fixed.