std::declval 関数テンプレート

C++0x では decltype によって「式の型」を得ることが出来ますが、
テンプレートメタプログラミングなんかで「ある型の変数を decltype 内で使いたい」って時には、
その変数をどうやって作るかが問題になります。


例えば T1 と T2 を乗算した結果の型が欲しいとかいう場合、
普通の型なら T1 と T2 が同じ型 T なら T になるでしょうが、
もしベクトルとか行列だったらダメですので、 decltype を使って取得したい。
でも、 decltype( T1 * T2 ) とは書けない。じゃあどうするか。


まず考えられるのが decltype( T1() * T2() ) ですが、
これは T1 と T2 に対して default constructible を要求してしまいますし、
T1 や T2 が参照型の場合にはダメダメです。


じゃあ T1 t1(); T2 t2(); という関数を作ってから、
decltype( t1() * t2() ) とすればいいじゃないか、というと、
それは T1 や T2 が noncopyable な場合にダメかもしれないし、
何より、イチイチ補助関数を定義するのが面倒です。


じゃあどうするかというと、ここはテンプレートで汎用的な補助関数を作ればよくて、

template<typename T>
T&& value_of();

という関数 value_of を作れば、後は
decltype( value_of() * value_of() ) とか書けて幸せ、
かと思いきや、今度は T が U&& の場合に困りますし、
そもそも、そういう補助関数は出来る事なら標準で欲しいよね。


と思ってたら、標準に declval ってのがありました。


規格: 20.3.4 Function template declval ( in N3092 p.491 )

template <class T>
  typename add_rvalue_reference<T>::type declval() noexcept; // as unevaluated


これを使えば、こう書けます:

decltype( std::declval<T1>() * std::declval<T2>() )


まぁ正直、普段は

template<typename T1, typename T2>
auto f( T1 && t1, T2 && t2 ) -> decltype( t1 * t2 );

とか書けばいいので、
あまり使わない関数かと思います。
でも、覚えておくと、いざ必要になったときにオレオレ補助関数を作らなくて済むので
幸せになれるかなーと思いました。


あ、ヘッダは です。