エミュレーションすると言っても、基本的に常時 false
ですが:
#include <boost/config.hpp> #ifdef BOOST_NO_NOEXCEPT // 今のところそんなマクロ無いけど #define NOEXCEPT(expr) ( sizeof( (void)( expr ), 0 ) < 0 ) #define NOEXCEPT_IF(expr) #define NOTHROW #else #define NOEXCEPT(expr) ( sizeof( (void)( expr ), 0 ) > 0 && noexcept(expr) ) // 本来ならば // #define NOEXCEPT(expr) noexcept(expr) // としたいところだが、 gcc-4.6.0 だと noexcept による SFINAE が上手く機能しない #define NOEXCEPT_IF(expr) noexcept(expr) #define NOTHROW noexcept #endif // 補助用に、単純なマクロを // ただし SFINAE は機能しなくなります #define NOEXCEPT_AS(expr) NOEXCEPT_IF( NOEXCEPT(expr) ) // 使い道 #include <utility> // 基本的に NOEXCEPT はテンプレートデフォルト引数内で評価する // x.swap(y) があるなら、それを使う template< class T, bool NoExcept = NOEXCEPT( std::declval<T&>().swap( std::declval<T&>() ) ) > void my_swap_( T& x, T& y, int ) NOEXCEPT_IF( NoExcept ) { x.swap( y ); } // なければ (std::)swap を使う using std::swap; template< class T, bool NoExcept = NOEXCEPT( swap( std::declval<T&>(), std::declval<T&>() ) ) > void my_swap_( T& x, T& y, ... ) NOEXCEPT_IF( NoExcept ) { swap( x, y ); } // 本体 template< class T > void my_swap( T& x, T& y ) NOEXCEPT_AS( my_swap_( std::declval<T&>(), std::declval<T&>(), 0 ) ) { my_swap_( x, y, 0 ); } #include <iostream> #include <memory> // for std::unique_ptr int main() { std::unique_ptr<int> p1, p2; std::cout << std::boolalpha; std::cout << NOEXCEPT( my_swap( p1, p2 ) ) << std::endl; }
NOEXCEPT( expr )
の場合、 expr が valid でなければ ill-formed になる(テンプレート中なら SFINAE が働く)ように工夫されています。
その用途に使う場合、 NOEXCEPT_IF
中で直接 使われた場合には SFINAE が働かないので、基本的にデフォルトテンプレート引数によって指定するべきです。((とはいえ、神経質になる必要がない場合(または、他の部分で decltype
等による SFINAE が行われている場合)には、普通に直接 NOEXCEPT_IF
内で使うのが楽でしょう。))
その工夫以外は全くもって trivial ですが、実用上はこの程度で十分かと思います。
また、簡便にコードを書くため、 expr と同じように例外を投げることを指定する NOEXCEPT_AS( expr )
も作ってみました。これも trivial ですが。
本音を言うなら、プリプロセッサメタプログラミングで
NOEXCEPT_AS( a, b, c )
が
NOEXCEPT_IF( NOEXCEPT(a) && NOEXCEPT(b) && NOEXCEPT(c) )
と展開されるようにしてみたかったのですが、僕の知識では無理でした。
追記 ( 25:40, 04/25 )
Boost.Config に noexcept
演算子の有無を問い合わせるマクロが無いのは おかしいと思ったので、
それを問い合わせるマクロ BOOST_NO_NOEXCEPT
を書いて Boost の ML に post してみました。
なので、順調に行けば、 Boost-1.47.0 から使えるようになる…といいなぁ。
それにあわせサンプルコードも微調整。
さらに追記 ( 23:00, 05/05 )
Boost の ML に送ったパッチが無事に適用されたようです.
なので,ケチがつかない限り, Boost-1.47.0 から使えるようになる筈です.
というわけで,
#if BOOST_VERSION < 104700 || defined( BOOST_NO_NOEXCEPT ) #define NOEXCEPT(expr) ( sizeof( (void)( expr ), 0 ) < 0 ) // ...
って感じにすれば,本格的に使えるようになりそうです.