template<class T> T&& declval() noexcept; template< class T > inline void f1( T& x ) noexcept( noexcept( declval<T&>().foo() ) ) { x.foo(); } template< class T, bool Noexcept = noexcept( declval<T&>().foo() ) > inline void f2( T& x ) noexcept( Noexcept ) { x.foo(); } // a common and trivial mistake template< class T > inline void f3( T& x ) noexcept( declval<T&>().foo() ) { x.foo(); } struct X { void foo(); }; struct Y { void foo() noexcept; }; struct Z {}; int main() { X x; Y y; Z z; static_assert( !noexcept( f1(x) ), "OK." ); static_assert( !noexcept( f2(x) ), "OK." ); // static_assert( !noexcept( f3(x) ), "shall be ill-formed(OK)." ); static_assert( noexcept( f1(y) ), "OK." ); static_assert( noexcept( f2(y) ), "OK." ); // static_assert( noexcept( f3(y) ), "shall be ill-formed(OK)." ); static_assert( noexcept( f1(z) ), "shall be ill-formed." ); static_assert( noexcept( f2(z) ), "shall be ill-formed." ); static_assert( !noexcept( f3(z) ), "shall be ill-formed." ); } --------------------- GCC-4.6.0 compiles this code successfully, but expressions "noexcept( f1(z) )", "noexcept( f2(z) )", and "noexcept( f3(z) )" shall be ill-formed, because unevaluated operand "declval<T&>().foo()" is ill-formed. This behavior prevents using noexcept for switching implementations by SFINAE: --------------------- // if x.swap(y) is exist, calls it. template<class T> void my_swap_( T& x, T& y, int ) noexcept( noexcept( std::declval<T&>().swap( std::declval<T&>() ) ) ) { x.swap( y ); } // otherwise, calls [std::]swap using std::swap; template<class T> void my_swap_( T& x, T& y, ... ) noexcept( noexcept( swap( std::declval<T&>(), std::declval<T&>() ) ) ) { swap( x, y ); } template<class T> void my_swap( T& x, T& y ) noexcept( noexcept( my_swap_( std::declval<T&>(), std::declval<T&>(), 0 ) ) ) { my_swap_( x, y, 0 ); } --------------------- Of course, this code can be written with another C++0x feature (e.g. decltype), I'd prefer to use noexcept when result type is void, because it's simple.
Author: jason Date: Thu Apr 7 21:48:00 2011 New Revision: 172148 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=172148 Log: PR c++/48468 * except.c (build_noexcept_spec): Propagate error_mark_node. (finish_noexcept_expr): Likewise. Added: trunk/gcc/testsuite/g++.dg/cpp0x/sfinae11.C Modified: trunk/gcc/cp/ChangeLog trunk/gcc/cp/except.c trunk/gcc/testsuite/ChangeLog trunk/gcc/testsuite/g++.dg/cpp0x/noexcept02.C
Author: jason Date: Fri Apr 8 15:02:16 2011 New Revision: 172194 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=172194 Log: PR c++/48468 * except.c (build_noexcept_spec): Propagate error_mark_node. (finish_noexcept_expr): Likewise. Added: branches/gcc-4_6-branch/gcc/testsuite/g++.dg/cpp0x/sfinae11.C Modified: branches/gcc-4_6-branch/gcc/cp/ChangeLog branches/gcc-4_6-branch/gcc/cp/except.c branches/gcc-4_6-branch/gcc/testsuite/ChangeLog branches/gcc-4_6-branch/gcc/testsuite/g++.dg/cpp0x/noexcept02.C
Fixed for 4.6.1.
Note that the fix I just checked in for 49107 delays substitution into noexcept-specifications, so they are no longer usable for SFINAE.