The following program becomes rejected when compiled with gcc 4.8.0 trunk using the flags: -Wall -pedantic (with or without -std=c++11) //-------------------------------- struct ostream { ostream& operator<<(int); }; struct sfinae_base { typedef char one; typedef char (&two)[2]; template<class T> static T make(); template<unsigned> struct ok { typedef int type; }; template<class U, class T> static one test(typename ok<sizeof( make<U>() << make<T>() )>::type); template<class, class> static two test(...); }; template<class T> struct is_printable : private sfinae_base { enum { value = sizeof(test<ostream&, T>(0)) == sizeof(one) }; }; typedef int ok[is_printable<int>::value ? 1 : -1]; int main() {} //-------------------------------- "Compilation finished with errors: source.cpp:31:49: error: size of array 'ok' is negative typedef int ok[is_printable<int>::value ? 1 : -1]; ^" It worked with gcc 4.7.2 (also with Clang 3.2 or Intel-13), so this looks like a regression to me. Operator<< is not the only one, I also noted problems with other operators (such as binary plus).
I just notice that the problem is not restricted to sizeof sfinae. In fact if we define the first test overload as follows: template<class U, class T> static one test(decltype( (make<U>() << make<T>()), 0 )); the same regression problem occurs. I'm confused.
The actually tested gcc version was 4.8.0 20130127 (experimental)
Let's mark it as such then.
Here are two further variants of the first overload that fail to work since 4.8.0 trunk: (a) template<class> struct res { typedef one type; }; template<class U, class T> static typename res<decltype(make<U>() << make<T>())>::type test(int); (b) template<class> struct res { typedef one type; }; template<class U, class T> static one test(typename res<decltype(make<U>() << make<T>())>::type*); Obviously the actual problem is not related to sizeof, so I changed the issue title accordingly.
I think I found the problem, the root is actually not related to sfinae (fortunately), but to the way how name-lookup in classes work in gcc. The problem can be fixed (as a workaround), if we move the static member function template<class T> static T make(); into namespace scope (as non-member function). I apologize for the lengthy thread within this issue. But it nonetheless is a regression, because that name-lookup worked correctly in previous versions of gcc.
Thanks Daniel. Next, we have to figure out which commit broke such lookups. I can work on that today (if nobody beats me)
Narrowed to r190095 - r190842 so far.
http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=190664
Further data about the root of the problem: It seems actually to be an access problem, the requirements for reproducing seem to be: 1) Some class B derives *privately* from a base class A 2) B refers to some function template f2 that refers to another dependent function template f1 both in class scope of A (It doesn't matter whether these function are actually public in A) A reduced example is as follows: //--------------------------- struct A { template<class T> static int f1(); template<class T> static int f2(char(*)[sizeof(f1<T>())]); }; struct B : private A { enum { value = sizeof(f2<int>(0)) }; }; //--------------------------- "Compilation finished with errors: source.cpp:10:35: error: no matching function for call to 'B::f2(int)' enum { value = sizeof(f2<int>(0)) }; ^ source.cpp:10:35: note: candidate is: source.cpp:6:15: note: template<class T> static int A::f2(char (*)[sizeof (f1<T>())]) static int f2(char(*)[sizeof(f1<T>())]); ^ source.cpp:6:15: note: template argument deduction/substitution failed: source.cpp: In substitution of 'template<class T> static int A::f2(char (*)[sizeof (f1<T>())]) [with T = int]': source.cpp:10:35: required from here source.cpp:3:15: error: 'static int A::f1() [with T = int]' is inaccessible static int f1(); ^ source.cpp:6:39: error: within this context static int f2(char(*)[sizeof(f1<T>())]); ^"
Author: jason Date: Wed Feb 6 03:33:45 2013 New Revision: 195779 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=195779 Log: PR c++/56208 * pt.c (fn_type_unification): Discard any access checks from substituting explicit args. Added: trunk/gcc/testsuite/g++.dg/cpp0x/sfinae43.C Modified: trunk/gcc/cp/ChangeLog trunk/gcc/cp/pt.c
Fixed.