サンプルの動作確認バージョン [GCC4.4/1.40.0] [VC9/1.40.0]
#include <string>
#include <boost/call_traits.hpp>
using namespace std;
template<typename T>
class Holder
{
public:
Holder() {}
typename boost::call_traits<T>::param_type get() { return data; }
void set( typename boost::call_traits<T>::param_type d ) { data = d; }
private:
T data;
};
int main()
{
Holder<int> hint;
hint.set( 100 );
int t = hint.get(); // getやsetは const int で受け渡し
Holder<string> hstr;
hstr.set( "hoge" );
string s = hstr.get(); // getやsetは const string& で受け渡し
return 0;
}
int
などの小さな型は関数の引数として渡すときには、
そのまま値渡しにしたほうが普通は効率的です。しかし、例えば vector
などのデカブツは毎回コピーしていては大変なことになります。そこで、
あたかも値渡しをしているかのように書けるけれど実際はポインタ渡し並に効率がよい
「const参照」 を用いるというのが、C++では一般的な手段となっています。
さて問題は、int
にも vector
にも使えるような、
汎用のtemplateを書くとき。型Tの受け渡しはどうすればよいでしょう?
const参照にしてしまうことが多いですが、int
や
double
で使うときを考えると、ちょっと勿体ない気もします。
そこで call_traits<T>::param_type
を使うと、
上記の例のように適切な方を選択して使うようにできるわけです。
もう一つ重要な機能として、「参照の参照」の回避があります。 効率がよいからという理由で片っ端からtemplateでconst参照を使っていると、 プログラムの中で「参照型への参照型」が出現してしまうことがよくあります。 で、これはC++的にはイリーガル。「constのconstは唯のconst」にしてくれる C++ が「参照への参照は唯の参照」と扱ってくれないのは猛烈に不満ですが、 現在の所は仕方がない。
解決策としては、「T&
」のかわりに
「call_traits<T>::reference
」を使うこと。
Tが既に参照型だった場合は call_traits<T>::reference
をとっても元の型のままになるように作られているので安心です。