メンバ変数の swap 呼び出しを自動化するテク

たぶん既にあるネタと思いますが、せっかくソースコード書いたので掲載します。


C++で本格的にプログラムを書く場合、ほとんど全てのクラスに swap 関数を実装することになります。
これは例外安全の要求(詳しくは Exceptional C++ を参照)もありますし、単純に、効率的な swap があれば様々なアルゴリズムの記述に便利、という側面もあります。
実際問題として、コピーは出来ないけど swap はできる、というクラスは非常に多く、そういったクラスでも擬似的に代入に近い動作を行える swap は、非常に重宝するわけですが、ここで問題があります。


swap 関数の実装って、長いソースコードではないにしろ、少し面倒じゃないですか?

struct hoge
{
  member1 mem1;
  member2 mem2;
  // and so on
  
  // nothrow swap
  void swap( hoge& other )
  {
    using std::swap();
    swap( mem1, other.mem1 );
    swap( mem2, other.mem2 );
    // and so on.
  }
  friend void swap( hoge& one, hoge& another ){ one.swap(another); }
};

こうやって各メンバごとに決まり文句を並べていくだけだから楽、と言えなくもないですが、もう少し記述量を減らすことができてもバチは当たらない筈です。


まぁ実際問題として記述量を減らす必要もあんまりないですが、一応そういうのもできるよ、って感じで試しに作ってみるのも、まあ悪くないでしょう。
というわけで、実際に作ってみました: http://codepad.org/N7oEMKJT

#include <algorithm> // for std::swap
#include <boost/preprocessor.hpp>

#define GEN_SWAP_( z, n, d ) \
  swap( one.*BOOST_PP_CAT(m, n), another.*BOOST_PP_CAT(m, n) );

#define GEN_( z, n, d )                                       \
  template<typename T, BOOST_PP_ENUM_PARAMS( n, typename M )> \
  void memberwize_swap( T& one, T& another,                   \
    BOOST_PP_ENUM_BINARY_PARAMS( n, M, m ) )                  \
  {                                                           \
    using std::swap;                                          \
    BOOST_PP_REPEAT_FROM_TO( 0, n, GEN_SWAP_, _ )             \
  }

BOOST_PP_REPEAT_FROM_TO( 1, 10, GEN_, _ )

#undef GEN_
#undef GEN_SWAP_

使い方:

struct hoge
{
  int i, j;
  
  hoge( int i_, int j_ )
    : i(i_), j(j_) {}
  
  void swap( hoge& other )
  {
    // 対象オブジェクトに加え swap する全てのメンバ変数へのポインタを渡す
    memberwize_swap( *this, other, &hoge::i, &hoge::j );
  }
  friend void swap( hoge& one, hoge& another )
  {
    one.swap(another);
  }

};

以上。メンバ変数の数が多くなってくると、一気に楽になるはずです。
ちなみにメンバ変数へのポインタを使ってるけど、最適化を有効にすれば全く普通の swap と同等の処理に展開してくれるので、コストを気にする場合も安心ですよっと。