[C++11]_[初級][左参照宣言と右参照宣言]
シーン: remove_reference構造体には右値参照の姿が見えます&&、では、ここの右値参照はいったい何の役に立つのでしょうか. はint&とint&&の2つの類似の応用タイプもよく発見され、1つ目は左値参照声明であり、2つ目は右値参照声明である. 以下の例を直接参照するcppreferenceは、すでに完全に書かれているので、書き直す必要はありません.
参照先:
1.Reference declaration 2.Rvalue Reference Declarator: && 3.Lvalue Reference Declarator: &
構文
左参照宣言:&attr(optional)declarator(1)右参照宣言:&&attr(optional)declarator(2)(since C++11)
左参照宣言&
–1. 左値参照は、オブジェクトの別名として理解することができ、左値参照は初期化され、再付与されない必要がある.
–2. 関数を呼び出す際には、参照パラメータとして用いることができる.
–3. 1つの関数の戻り値が左の値である場合、この関数の呼び出し式は左の値式とみなすことができる.
右参照宣言&&
–1. 右参照宣言は、左と右を区別できます.-2.右の値は、Moveの意味が実現するまで、一時的なオブジェクト(一般的には参照できない)のリソースを他の場所に移動することができる.
–3. 右の値の参照は、一時オブジェクトのライフサイクルを拡張するためにも使用できます.
–4. 関数に左値と右値が参照するリロードがある場合、呼び出し時に呼び出しが一致し、左値が左値のリロードを呼び出し、右値が右値のリロードを呼び出す.これにより、Move ConstructorとMove Assignmentの実現をサポートすることができる.
参照先:
1.Reference declaration 2.Rvalue Reference Declarator: && 3.Lvalue Reference Declarator: &
構文
左参照宣言:&attr(optional)declarator(1)右参照宣言:&&attr(optional)declarator(2)(since C++11)
左参照宣言&
–1. 左値参照は、オブジェクトの別名として理解することができ、左値参照は初期化され、再付与されない必要がある.
#include <iostream>
#include <string>
int main()
{
std::string s = "Ex";
std::string& r1 = s;
const std::string& r2 = s;
r1 += "ample"; // modifies s
// r2 += "!"; // error: cannot modify through reference to const
std::cout << r2 << '
'; // prints s, which now holds "Example"
}
–2. 関数を呼び出す際には、参照パラメータとして用いることができる.
#include <iostream>
#include <string>
void double_string(std::string& s)
{
s += s; // 's' is the same object as main()'s 'str'
}
int main()
{
std::string str = "Test";
double_string(str);
std::cout << str << '
';
}
–3. 1つの関数の戻り値が左の値である場合、この関数の呼び出し式は左の値式とみなすことができる.
#include <iostream>
#include <string>
char& char_number(std::string& s, std::size_t n)
{
return s.at(n); // string::at() returns a reference to char
}
int main()
{
std::string str = "Test";
char_number(str, 1) = 'a'; // the function call is lvalue, can be assigned to
std::cout << str << '
';
}
右参照宣言&&
–1. 右参照宣言は、左と右を区別できます.-2.右の値は、Moveの意味が実現するまで、一時的なオブジェクト(一般的には参照できない)のリソースを他の場所に移動することができる.
–3. 右の値の参照は、一時オブジェクトのライフサイクルを拡張するためにも使用できます.
#include <iostream>
#include <string>
int main()
{
std::string s1 = "Test";
// std::string&& r1 = s1; // error: can't bind to lvalue
const std::string& r2 = s1 + s1; // okay: lvalue reference to const extends lifetime
// r2 += "Test"; // error: can't modify through reference to const
std::string&& r3 = s1 + s1; // okay: rvalue reference extends lifetime
r3 += "Test"; // okay: can modify through reference to non-const
std::cout << r3 << '
';
}
–4. 関数に左値と右値が参照するリロードがある場合、呼び出し時に呼び出しが一致し、左値が左値のリロードを呼び出し、右値が右値のリロードを呼び出す.これにより、Move ConstructorとMove Assignmentの実現をサポートすることができる.
#include <iostream>
#include <utility>
void f(int& x)
{
std::cout << "lvalue reference overload f(" << x << ")
";
}
void f(const int& x)
{
std::cout << "lvalue reference to const overload f(" << x << ")
";
}
void f(int&& x)
{
std::cout << "rvalue reference overload f(" << x << ")
";
}
int main()
{
int i = 1;
const int ci = 2;
f(i); // calls f(int&)
f(ci); // calls f(const int&)
f(3); // calls f(int&&)
// would call f(const int&) if f(int&&) overload wasn't provided
f(std::move(i)); // calls f(int&&)
}