Hello, I've noticed some strange behavior regarding C++ SFINAE that I believe may not be ISO-14882 compliant. I've tried to get a minimal example to reproduce the compilation errors I'm getting, but some explanation is needed.
I'm working on a boolean metafunction to detect nested member templates. I'm basically following the example of detecting nested types from comp.lang.c++.moderated USENET postings from Rani Sharoni (2002-03-17, http://tinyurl.com/2u2a9f) and Aleksey Gurtovoy (2002-03-19, http://tinyurl.com/376y7c). Also, the 3rd code example in section 14.8.2 of the standard especially illustrates what I'm trying to do. There's been some discussion on the Boost mailing list on the thread archived at http://tinyurl.com/39cvhc. I'll first show a working example. Then I'll show two examples that perhaps should work but instead generate compilation errors. The following example works. $ g++ -dumpversion 4.1.2 $ cat sfinae_success.cc typedef char (&yes)[1]; typedef char (&no) [2]; template<class T> struct type_substitute {}; template<template <class T, class U> class> struct biary_template_substitute {}; template<class T, class U, class V> struct has_xxx { template<class W> static no test( type_substitute<W>*, ... ); template<class W> static yes test( type_substitute<W>*, biary_template_substitute< W::template xxx >* ); static const bool value = sizeof(test<T>(0, 0)) == sizeof(yes); }; struct foo { template<class U, class V> struct xxx; }; struct bar { template<class U, class V> struct yyy; }; struct baz { template<class U> struct xxx; }; int main() { int assert_has_xxx[has_xxx<foo, int, int>::value]; int assert_not_xxx[!has_xxx<bar, int, int>::value]; int assert_not_unary[!has_xxx<baz, int, int>::value]; } $ g++ -std=c++98 -pedantic sfinae_success.cc $ However, the following changes introduce a compilation error. $ diff -c sfinae_success.cc sfinae_error1.cc *** sfinae_success.cc 2007-04-04 11:21:10.000000000 -0400 --- sfinae_error1.cc 2007-04-04 11:21:10.000000000 -0400 *************** *** 10,25 **** struct has_xxx { template<class W> static no test( ! type_substitute<W>*, ... ); template<class W> static yes test( ! type_substitute<W>*, ! biary_template_substitute< ! W::template xxx ! >* ); static const bool value --- 10,23 ---- struct has_xxx { template<class W> static no test( ! W*, ... ); template<class W> static yes test( ! W*, ! typename W::template xxx<U,V>* ); static const bool value $ g++ -std=c++98 -pedantic sfinae_error1.cc sfinae_error1.cc: In instantiation of 'const bool has_xxx<baz, int, int>::value': sfinae_error1.cc:43: instantiated from here sfinae_error1.cc:24: error: wrong number of template arguments (2, should be 1) sfinae_error1.cc:36: error: provided for 'template<class U> struct baz::xxx' $ If you cast the first argument to test() instead of explicitly calling test<T>(0, 0), then gcc no longer issues the error above. However, overload resolution no longer chooses the intended function overload. $ diff -c sfinae_error1.cc sfinae_error2.cc *** sfinae_error1.cc 2007-04-04 11:21:10.000000000 -0400 --- sfinae_error2.cc 2007-04-04 11:21:10.000000000 -0400 *************** *** 21,27 **** ); static const bool value ! = sizeof(test<T>(0, 0)) == sizeof(yes); }; struct foo { --- 21,27 ---- ); static const bool value ! = sizeof(test((T*)0, 0)) == sizeof(yes); }; struct foo { $ g++ -std=c++98 -pedantic sfinae_error2.cc sfinae_error2.cc: In function 'int main()': sfinae_error2.cc:41: error: ISO C++ forbids zero-size array 'assert_has_xxx' $ Are either or both of these errors the result of non standard compliant bugs in gcc? If not, what's the explanation? If so, let me know if you'd like me to fill out a bug report. Thanks! Daniel Walker