noexcept を(半ば強引に)エミュレーションするマクロ

エミュレーションすると言っても、基本的に常時 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 )
  // ...

って感じにすれば,本格的に使えるようになりそうです.