class A { int a; };
template<typename, typename = void>
class test {};
template<typename T>
class test<T,decltype(T::a)> {};
int main() { test<A> a; }
The code above compiles without error on clang version 3.8.0-2ubuntu4 (tags/RELEASE_380/final)
, but fails to compile on g++-5 (Ubuntu 5.4.1-2ubuntu1~16.04) 5.4.1 20160904
and g++-6 (Ubuntu 6.2.0-3ubuntu11~16.04) 6.2.0 20160901
with errors like this:
main.cpp: In function ‘int main()’:
main.cpp:9:22: error: ‘int A::a’ is private within this context
int main() { test<A> a; }
^
main.cpp:1:15: note: declared private here
class A { int a; };
In both cases I compiled with -std=c++11
, but the effect is the same for -std=c++14
and -std=c++1z
.
Which compiler is correct here? I assumed that, at least since C++11, accessing private members during template substitution should trigger SFINAE, implying that clang is correct and gcc is not. Is there some additional rule I am unaware of?
For referencce, I am thinking of the note in §14.8.2/8 of the current standard draft N4606:
If a substitution results in an invalid type or expression, type deduction fails. An invalid type or expression is one that would be ill-formed, with a diagnostic required, if written using the substituted arguments. [ Note: If no diagnostic is required, the program is still ill-formed. Access checking is done as part of the substitution process. — end note ]
Using a member function and a member function pointer instead is accepted by both compilers:
class A { void a() {}; };
template<typename, typename = void>
class test {};
template<typename T>
class test<T,decltype(&T::a)> {};
int main() { test<A> a; }