Boost logo

Boost Users :

Subject: Re: [Boost-users] puzzle with enable_if
From: Gevorg Voskanyan (v_gevorg_at_[hidden])
Date: 2010-04-20 14:22:37


John Dlugosz wrote: > Hmm, I still > think that the template expansion of cases 1 and 2 would "choke" in the same > way. But the difference, I think, must be one of indirection: Case > 1, the template instantiation of enable_if fails while directly seeing if it > forms a usable return type. In Case 2, it fails as a nested invocation, a > type needed by the (possible) instantiation of the return type of the > function. > As for the difference between 2 and 3, "once the class is > known, do individual members including nested types make sense"? seems to be > more arbitrary, like the compiler takes some things but not others. I > don't see how that difference is explained in the standard. > Thanks for your detailed analysis. > --John C++03 14.8.2/2 explicitly lists a finite set of kinds of errors which cause deduction failure and thus SFINAE, but it is not clear on the contexts in which those kind of errors cause deduction failure instead of a hard error. As a template class instantiation can fail due to far more kinds of errors (not only invalid types and invalid expressions, but also invalid member declarations, invalid base classes etc.) than those listed as causing type deduction failure, it can be assumed that all kinds of errors occurring while instantiating template classes cause hard errors, as it probably would be surprising if some errors in that context cause deduction failures and others hard errors. Consider the following example: template < typename T > struct A { typedef T type; typename T::value_type value; /*if T is double, attempting to use a type that is not a class type in a qualified name, which is a kind of error included in the set of those causing deduction failure*/ }; template < typename T > struct B { typedef T type; static const T value = T(1); /*if T is double, attempting to supply an initializer for static data member that is not of integral or enumeration type, which is NOT a kind of error included in the set of those causing deduction failure*/ }; template < typename T > struct C : T {/*if T is double, attempting to inherit from non-class type, which is NOT a kind of error included in the set of those causing deduction failure*/ typedef T type; }; template < typename T > typename A< T >::type f( T ); void f( ... ); template < typename T > typename B< T >::type g( T ); void g( ... ); template < typename T > typename C< T >::type h( T ); void h( ... ); int main() { f( 5.0 );// SFINAE or hard error? g( 6.0 );// SFINAE or hard error? h( 7.0 );// SFINAE or hard error? } I think it would not be consistent if the call to f() here resulted in SFINAE but the calls to g() and h() produced hard errors instead, so that's why I assume C++03 did not intend errors in external template instantiations to result in SFINAE. Fortunately, based on http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2634.html, C++1x makes that explicit, as it (latest draft n3090/FCD) adds the following lines to the relevant paragraph: "Only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a deduction failure. [ Note: The evaluation of the substituted types and expressions can result in side effects such as the instantiation of class template specializations and/or function template specializations, the generation of implicitly-defined functions, etc. Such side effects are not in the “immediate context” and can result in the program being ill-formed.—end note ]" Hope this helps, Gevorg


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net