http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48468
Summary: [C++0x][SFINAE] noexcept operator does handle function templates well Product: gcc Version: 4.6.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ AssignedTo: unassig...@gcc.gnu.org ReportedBy: gintensub...@gmail.com 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.