Perfect Forward を行ってくれるマクロ

C++0x の Perfect Forward は,便利なのですが,イチイチ変数の型名を指定しなきゃいけないのが面倒です:

#include <utility>

template< class T, class U >
auto add( T && x, U && y )
  -> decltype( std::forward<T>(x) + std::forward<U>(y) )
{
  return std::forward<T>(x) + std::forward<U>(y);
}

もちろん,これには深い理由があるわけですが,でも手動で指定するのは面倒ですし,ミスの元.


というわけで,型指定を自動で行ってくれるマクロを,適当に書いてみました:

// 定義
#include <utility>
#define STD_FORWARD(x) std::forward<decltype(x)>(x)

// 使い方
template< class T, class U >
auto add( T && x, U && y )
  -> decltype( STD_FORWARD(x) + STD_FORWARD(y) )
{
  return STD_FORWARD(x) + STD_FORWARD(y);
}

https://github.com/gintenlabo/pezzi/blob/master/forward.cc


Variadic Templates でも,きちんと動作します:

// 例として http://d.hatena.ne.jp/gintenlabo/20110628/1309221610 の make_unique_lock を
template< class Mutex, class... Args >
inline std::unique_lock<Mutex> make_unique_lock( Mutex& m, Args&&... args ) {
  return std::unique_lock<Mutex>( m, STD_FORWARD(args)... );
}


また,引数が値渡しや const& であっても,問題ありません.
通常の Perfect Forward と同様に,値渡しの場合は move され,参照渡しの場合にはそのまま渡されます.((とはいえ,その場合は std::move を使うか,そのまま渡すべきでしょう.))


また,ローカル変数に対して適用することもでき,その場合,そのローカル変数が値なら move され,参照なら適切に forward されます:

int main()
{
  std::string s = "hoge";

  {
    std::string t = s;
    some_function( STD_FORWARD(t) ); // 変数 t はこれ以上使わないので, move してよい
  }

  {
    std::string& r = s;
    some_function( STD_FORWARD(r) ); // 変数 r 自身はこれ以上使わないが,参照なので move してはいけない
  }

  {
    std::string&& r = std::move(s);  // s を move しているので,これ以降 s を使ってはいけない
    some_function( STD_FORWARD(r) ); // r は参照だが,参照先の s が既に move されてるので, move してよい
  }

}


と,なんとなく便利そうに見えますが,あくまでマクロなので,普通は使わないほうがいいと思います.