Effective Modern C++
Item 24: Distinguish universal references from
rvalue references.
@mooopan
自己紹介
• 藤田康博(@mooopan)
• 株式会社Preferred Networks エンジニア
• C++でゲームのAIを書いたり機械学習したり
Item 24: Distinguish universal
references from rvalue references.
• T&& (Tは型)は文脈によって2つの意味を持つ
• Rvalue reference
• Universal reference
• この2つを区別できるようになろう!
Rvalue reference
• 右辺値にのみ束縛される
// no error
int&& x = 0;
int a = 0;
// error: cannot bind 'int' lvalue to
'int&&'
int&& y = a;
Universal reference
• 右辺値にも左辺値にも束縛される
auto&& x = 0; // no error
int a = 0;
auto&& y = a; // no error
• (const/non-const,volatile/non-volatile関係な
くなんにでも束縛される→universal)
Universal referenceの働き
• lvalueで初期化するとlvalue referenceに,rvalueで初期
化するとrvalue referenceになる
// param is a universal reference
template<typename T>
void f(T&& param);
Widget w;
// param's type is Widget&, an lvalue
reference
f(w);
// param's type is Widget&&, an rvalue
reference
f(std::move(w));
Universal referenceが
現れる2つの文脈
• テンプレートパラメータ
// param is a universal reference
template<typename T>
void f(T&& param);
• auto宣言
// x is a universal reference
int a = 0;
auto&& x = a;
• 共通点:型推論の存在
Universal referenceでない例
• T&& の形をしていても型推論が起こらなければ
universal referenceではない
// no type deduction;
// param is an rvalue reference
void f(Widget&& param);
// no type deduction;
// param is an rvalue reference
Widget&& var1 = Widget();
見分け方
• もし変数やパラメータの型宣言が正確に T&& (た
だしTは推論される型)という形なら,それは
universal reference.
紛らわしい例 (1)
• 正確に T&& の形になっている必要がある
// param is an rvalue reference
template<typename T>
void f(std::vector<T>&& param);
// param is an rvalue reference
template<typename T>
void f(const T&& param);
紛らわしい例 (2)
• テンプレートを使っていて正確に T&& の形になってい
てもuniversal referenceではない場合がある
template<class T, class Allocator =
allocator<T>>
class vector {
public:
// x is an rvalue reference
void push_back(T&& x);
};
• Tはvectorの実体化の際に決まり,push_backで型推
論は起こらない
紛らわしい例 (3)
• Variadic templateのtemplate parameter packも
universal referenceになりうる
template<class T, class Allocator =
allocator<T>>
class vector {
public:
// args are zero or more universal
references
template <class... Args>
void emplace_back(Args&&... args);
};
紛らわしい例 (4)
• Generic lambdaの引数ではauto&&の形をとる
// func is a universal reference
// params are zero or more universal
references
auto timeFuncInvocation =
[](auto&& func, auto&&... params)
{...};
ここまで全部嘘
• Universal referenceという種類の参照があるわけ
ではない
• 実際に起こっているのはreference collapsing
(Item 30で扱う)
• しかし便利な概念なので後の章でも使う
まとめ
• 関数テンプレートパラメータの型が T&& (Tは推論
される型)だったりオブジェクトがauto&&を使って
宣言されたりしたら,それはuniversal reference.
• 正確に T&& の形になっていなかったりTの型推論が
起こらない場合はただのrvalue reference.
• Universal referenceはrvalueで初期化されれば
rvalue referenceに対応するしlvalueで初期化され
ればlvalue referenceに対応する

Effective Modern C++ Item 24: Distinguish universal references from rvalue references.