僕「&&
ってなに?」
僕「C++のコード、&&
みたいな記号をたまに見かけるけど、これは何なんだろう・・・」
女の子「ああ、それは__右辺値参照__(、ユニバーサル参照)を宣言するときの記号だよ~」
僕「右辺値参照?」
女の子「&
を使って参照を宣言できることは知ってるじゃん?」
僕「うん」
女の子「それは、__左辺値参照__なの」
女の子「同じように、&&
を使って宣言された参照型が__右辺値参照__なのだ」
int a;
int & b = a; // 左辺値参照
int && c = 0; // 右辺値参照
女の子「そして、__左辺値__は__左辺値参照__を初期化、右辺値__は__右辺値参照__を初期化することができて」
女の子「これらは一般に参照と呼ばれるの」
女の子「これだけの違いで、実際にこれらの参照を__使うときの意味は同じ」
僕「なるほど~ところで、左辺値、__右辺値__ってなに?」
女の子「それは__式__の種類」
僕「なにがちがうの?」
女の子「うーん、簡単にはいえないな~」
値カテゴリ
(僕「ちょっと気になったんだけど、式って言った?値じゃなくて?」)
(女の子「厳密にいえばそう。 左辺値、右辺値は、その名前に反して式の分類なのだよ」)
女の子「たとえば、下の図は式の分類である値カテゴリの全体図(N3337 3.10 図1のコピペ)」
女の子「式はglvalue
、rvalue
に分類することができて、それらはさらにlvalue
、xvalue
、prvalue
に分類することができるん」
女の子「詳しくは値カテゴリ - cppreference.comに書いてあるので、簡単な説明だけするね」
女の子「すごく簡単に言えば、」
-
lvalue
(左辺値) : 式にアドレスをとれるもの。代表的なのは、変数、関数の名前 -
xvalue
: 一時オブジェクト、std::move(x)
など -
prvalue
: アドレスが取れないもの。代表的には、戻り値の型が参照でない関数呼び出し式など -
rvalue
(右辺値) :prvalue
またはxvalue
のいずれか -
glvalue
:lvalue
またはxvalue
女の子「だよ」
僕「ううん・・・オブジェクトの名前とかなら__左辺値__、関数呼び出しみたいなのなら__右辺値__でおk?」
女の子「だいたいおk」
ユニバーサル参照(forwarding reference)
~数日後~
僕「なんだか謎味深いコード見つけたんだけど・・・」
女の子「どしたん」
僕「これみて・・・」
#include <iostream>
#include <string>
template<typename T>
void print(T&& arg) // <--
{
std::cout << std::forward<decltype(arg)>(arg) << '\n';
}
int main()
{
std::string str = "nyan";
print(str);
}
僕「この&&
、どう見ても右辺値参照なんだけど、普通に動くんだよこのコード・・・」
女の子「あー、このT&&
は__ユニバーサル参照(forwarding reference)__って呼ばれているものだね~」
女の子「template
とか、auto
に&&
がくっついてるのは、とりあえずなんでも受け取れるのだよ」
僕「まじか・・・」
女の子「そう」
僕「でも、なんで?」
女の子「この挙動の本質っぽいものは、__参照の圧縮__って呼ばれているものなの」
女の子「この場合、T
はstd::string &
に推論されるけど、このT
って&&
くっついてるじゃん?」
僕「うん」
女の子「でも参照の参照って作れないじゃん?」
僕「うん」
女の子「だから、コンパイラさんが気を利かせて、いい感じに推論してくれるんだよ~」
女の子「そんな感じで、T
はstd::string &
に推論されて、」
女の子「T&&
もいい感じにstd::string &
になるのだよ」
僕「はえ~」
(女の子「ちなみに、T&&
で受け取って、std::forward
でほかの関数の引数にそのまま渡すのは、」)
(女の子「__完全転送__って呼ばれるてるよ~」)
ちょっと注意
- ユニバーサル参照(forwarding reference)はなんでも受け取れてしまうので、オーバーロードがこれに解決しがちだよ
- (完全転送の
std::forward
は、std::move
と同じように同じものに対して何回もやっちゃダメだよ!)
参考リンク
ムーブセマンティクスについて -> 本当は怖くないムーブセマンティクス - yohhoyの日記(別館)
完全転送について-> C++のムーブと完全転送を知る - Fixstars Tech Blog /proc/cpuinfo
値カテゴリについて -> 値カテゴリ - cppreference.com
いろいろ -> 右辺値参照・ムーブセマンティクス - cpprefjp C++日本語リファレンス