eldeshの日記: 右辺値参照2/N(typo修正)
perfect fowarding
[左右]辺値参照とconstの有無でオーバーロードした関数に,
引数を転送するテンプレート関数を書きたいときに使用する転送テンプレート関数の書き方.
void hoge( string & );
void hoge( string const & );
void hoge( string && );
void hoge( string const && );
template< typename T >
void trans_hoge( T&& t ){
hoge(t);
}
string str("hoge"); // 左辺値
const string cstr("foo"); // constな左辺値
string bar(void){
return "bar";
}
string const bazz(void){
return "bazz";
}
trans_hoge(str); // hoge(string&)
trans_hoge(cstr); // hoge(string const&)
trans_hoge(bar()); // hoge(string&) !!
trans_hoge(bazz()); // hoge(string const&) !!
となって,左辺値参照Ver.が呼ばれてしまう.
なぜなら,hoge(t) tという名前が付いてるから(右辺値ではない)
これを回避するためには再度,名前を無くせば良い.
template< typename A >
struct Identity { // id a = a
typedef A type;
};
template< typename T >
T&& Forward( Identity<T>::type&& t ){ // reference collapsing 回避
return(t);
}
template< typename T >
void trans_hoge( T&& t ){
// 名前が無くなる
hoge(Forward<T>(t)); // 必ず<T>を明示
}
trans_hoge(bar()); // hoge(string&&) 計画通り!!
trans_hoge(bazz()); // hoge(string const&&) 計画通り!!
Identity::typeに無理やり&&を付与しているので,
reference collapsingが働かない.(なんで働かないのか厳密にはよく分からないorz)
ここで,通常の推論に任せると,trans_hogeの引数tの型はT&となるので,
Identity::type&&が参照の参照型となりコンパイルエラーとなってしまう.
これを回避するために,Forwardのパラメータ型は明示する必要がある.
Move semantics
右辺値参照の真髄(だと思う). 右辺値参照の参照先からリソースの所有権(つーかポインタ)を強奪する.
以下のような感じで使う.
class C {
public:
int *m_p;
C(int x) : x_(new int(x)) // a
{}
C( C& t ) : x_(new int(*t.m_p)) // b
{]
C( C&& t ) { // c
m_p = *t.m_p;
t.m_p = NULL;
}
};
class wrapperC {
C m_c;
public:
wrapperC(int x) : m_c(x){}
wrapperC( C&& c ) : m_c(Move(c)) {}
wrapperC( C& c ) : m_c(Move(c)) {}
wrapperC( wrapperC&& c ) : m_c(Move(c)) {}
};
C createC(int x){
C c(x);
return c;
}
wrapperC c0(5); // メソッドaが使われる
wrapperC c1(c0); // メソッドbが(ry
wrapperC c2( createC(6) ); // メソッドc(ry
wrapperC c2 = createC(7); // c(ry
03ではcreateC()でインスタンスが作られ,C(C&)でコピーされてから破棄されるが,
右辺値参照は,そこで破棄されるはずの一時変数に言及できるので,
ポインタ(メンバ)を横取りするだけでinstantiateが完了する.(代入も同じ)
さらにコンストラクタにMoveを書くだけで,
右辺値が来たときは勝手にMoveSemanticsが発動(?)し,
左辺値が来たときはコピーが動く!
とりあえずここまでで終了.(題名のNは2ということで)
だいたい理解したと思う.
まとめ:右辺値でおk
# 疲れた。
Mon Jul 6 14:29:58 2009 - wrapperCクラスのコンストラクタ名を修正.ひどいtypoだった….
右辺値参照2/N(typo修正) More ログイン