22
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

僕「参照の && ってなに?」

Last updated at Posted at 2019-04-21

僕「&&ってなに?」

僕「C++のコード、&&みたいな記号をたまに見かけるけど、これは何なんだろう・・・」
女の子「ああ、それは__右辺値参照__(、ユニバーサル参照)を宣言するときの記号だよ~」
僕「右辺値参照?」
女の子「&を使って参照を宣言できることは知ってるじゃん?」
僕「うん」
女の子「それは、__左辺値参照__なの」
女の子「同じように、&&を使って宣言された参照型が__右辺値参照__なのだ」

int a;
int & b = a;  // 左辺値参照
int && c = 0; // 右辺値参照

女の子「そして、__左辺値__は__左辺値参照__を初期化、右辺値__は__右辺値参照__を初期化することができて」
女の子「これらは一般に参照と呼ばれるの」
女の子「これだけの違いで、実際にこれらの参照を__使うときの意味は同じ

僕「なるほど~ところで、左辺値、__右辺値__ってなに?」
女の子「それは__式__の種類」
僕「なにがちがうの?」
女の子「うーん、簡単にはいえないな~」

値カテゴリ

(僕「ちょっと気になったんだけど、式って言った?値じゃなくて?」)
(女の子「厳密にいえばそう。 左辺値、右辺値は、その名前に反して式の分類なのだよ」)

女の子「たとえば、下の図は式の分類である値カテゴリの全体図(N3337 3.10 図1のコピペ)」

Expression category taxonomy

女の子「式はglvaluervalueに分類することができて、それらはさらにlvaluexvalueprvalueに分類することができるん」
女の子「詳しくは値カテゴリ - 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&&がくっついてるのは、とりあえずなんでも受け取れるのだよ」
僕「まじか・・・」
女の子「そう」

僕「でも、なんで?」
女の子「この挙動の本質っぽいものは、__参照の圧縮__って呼ばれているものなの」
女の子「この場合、Tstd::string &に推論されるけど、このTって&&くっついてるじゃん?」
僕「うん」
女の子「でも参照の参照って作れないじゃん?」
僕「うん」
女の子「だから、コンパイラさんが気を利かせて、いい感じに推論してくれるんだよ~」
女の子「そんな感じで、Tstd::string &に推論されて、」
女の子「T&&もいい感じにstd::string &になるのだよ」
僕「はえ~」

(女の子「ちなみに、T&&で受け取って、std::forwardでほかの関数の引数にそのまま渡すのは、」)
(女の子「__完全転送__って呼ばれるてるよ~」)

ちょっと注意

  1. ユニバーサル参照(forwarding reference)はなんでも受け取れてしまうので、オーバーロードがこれに解決しがちだよ
  2. (完全転送のstd::forwardは、std::moveと同じように同じものに対して何回もやっちゃダメだよ!)

参考リンク

ムーブセマンティクスについて -> 本当は怖くないムーブセマンティクス - yohhoyの日記(別館)
完全転送について-> C++のムーブと完全転送を知る - Fixstars Tech Blog /proc/cpuinfo
値カテゴリについて -> 値カテゴリ - cppreference.com
いろいろ -> 右辺値参照・ムーブセマンティクス - cpprefjp C++日本語リファレンス

22
13
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?