# 值類別，以及其參考Value categories, and references to them

## lvalue 具有身分識別An lvalue has identity

lvalue 具有身分識別。An lvalue has identity. 現在只關乎歷史價值："lvalue" 中的 "l" 是 "left" 的縮寫 (就像，在指派的左手邊)。It's now a matter of only historical interest that the "l" in "lvalue" is an abbreviation of "left" (as in, the left-hand-side of an assignment). 在C++，lvalue 可以出現在指派的左邊「或」 右邊。In C++, an lvalue can appear on the left or on the right of an assignment. 然後，"lvalues" 中的 "L" 實際上不會幫助您理解或定義其意義。The "l" in "lvalues", then, doesn't actually help you to comprehend nor define what they are. 您只需要了解我們所謂的 lvalue 是具有身分識別的值。You need only to understand that what we call an lvalue is a value that has identity.

lvalue 的運算式範例包括：具名的變數或常數；或可傳回參考的函式。Examples of expressions that are lvalues include: a named variable or constant; or a function that returns a reference. 「不是」 lvalue 的運算式範例包括：暫存項目；或可依照值傳回資料的函式。Examples of expressions that are not lvalues include: a temporary; or a function that returns by value.

``````int& get_by_ref() { ... }
int get_by_val() { ... }

int main()
{
std::vector<byte> vec{ 99, 98, 97 };
std::vector<byte>* addr1{ &vec }; // ok: vec is an lvalue.
int* addr2{ &get_by_ref() }; // ok: get_by_ref() is an lvalue.

int* addr3{ &(get_by_ref() + 1) }; // Error: get_by_ref() + 1 is not an lvalue.
int* addr4{ &get_by_val() }; // Error: get_by_val() is not an lvalue.
}
``````

## rvalue 可移動；lvalue 不可移動An rvalue is movable; an lvalue is not

"rvalue" 中的 "r" 是 "right" 的縮寫 (就像，在指派的右手邊)。The "r" in "rvalue" is an abbreviation of "right" (as in, the right-hand-side of an assignment). 但您可以在指派之外使用 rvalue，以及 rvalue 的參考。But you can use rvalues, and references to rvalues, outside of assignments. 然而，"rvalues" 中的 "r" 不是要聚焦的項目。The "r" in "rvalues", then, is not the thing to focus on. 您只需要了解我們所謂的 rvalue 是可移動的值。You need only to understand that what we call an rvalue is a value that is movable.

## Rvalue 參考和參考繫結規則Rvalue references, and reference-binding rules

``````template<typename T> T& get_by_lvalue_ref() { ... } // Get by lvalue (non-const) reference.
template<typename T> void set_by_lvalue_ref(T&) { ... } // Set by lvalue (non-const) reference.
``````

lvalue 參考可以繫結至 lvalue，但不可繫結至 rvalue。An lvalue reference can bind to an lvalue, but not to an rvalue.

``````template<typename T> T const& get_by_lvalue_cref() { ... } // Get by lvalue const reference.
template<typename T> void set_by_lvalue_cref(T const&) { ... } // Set by lvalue const reference.
``````

lvalue const 參考可以繫結至 lvalue 或 rvalue。An lvalue const reference can bind to an lvalue or to an rvalue.

``````template<typename T> T&& get_by_rvalue_ref() { ... } // Get by rvalue reference.
struct A { A(A&& other) { ... } }; // A move constructor takes an rvalue reference.
``````

rvalue 參考會繫結至 rvalue。An rvalue reference binds to an rvalue. 事實上，就多載解析而論，rvalue「偏好」 繫結至 rvlue 參考 (相較於 lvalue const 參考)。In fact, in terms of overload resolution, an rvalue prefers to be bound to an rvalue reference than to an lvalue const reference. 但是 rvlue 參考無法繫結至 lvalue，因為我們已經說過，rvlue 參考會參照假設我們不需要保留其內容的值 (例如，移動建構函式的參數)。But an rvalue reference can't bind to an lvalue because, as we've said, an rvalue reference refers to a value whose contents it's assumed we don't need to preserve (say, the parameter for a move constructor).

## glvalue 具有身分識別；prvalue 則不具備A glvalue has identity; a prvalue does not

``````int& get_by_ref() { ... }
int get_by_val() { ... }

int main()
{
int* addr3{ &(get_by_ref() + 1) }; // Error: get_by_ref() + 1 is a prvalue.
int* addr4{ &get_by_val() }; // Error: get_by_val() is a prvalue.
}
``````

## 值類別的全貌The complete picture of value categories

### glvalue (i)glvalue (i)

glvalue (廣義 lvalue) 具有身分識別。A glvalue (generalized lvalue) has identity.

### lvalue (i&!m)lvalue (i&!m)

lvalue (一種 glvalue) 具有身分識別，但不是可移動。An lvalue (a kind of glvalue) has identity, but isn't movable. 這些通常是您依照參考或依照 const 參考，或依照值 (如果複製成本低廉) 傳遞的讀寫值。These are typically read-write values that you pass around by reference or by const reference, or by value if copying is cheap. lvalue 無法繫結至 rvalue 參考。An lvalue can't be bound to an rvalue reference.

### xvalue (i&m)xvalue (i&m)

xvalue (一種 glvalue，但也是一種 rvalue) 具有身分識別，也可移動。An xvalue (a kind of glvalue, but also a kind of rvalue) has identity, and is also movable. 這可能是您先前因為複製成本昂貴而決定要移動的 lvalue，您得小心之後不要存取它。This might be an erstwhile lvalue that you've decided to move because copying is expensive, and you'll be careful not to access it afterward. 以下顯示如何將 lvalue 轉換成 xvalue。Here's how you can turn an lvalue into an xvalue.

``````struct A { ... };
A a; // a is an lvalue...
static_cast<A&&>(a); // ...but this expression is an xvalue.
``````

``````struct A { int m; };
A&& f();
f(); // This expression is an xvalue...
f().m; // ...and so is this.
``````

### prvalue (!i&m)prvalue (!i&m)

Prvalue (單純；一種 rvalue) 沒有身分識別，但可移動。A prvalue (pure rvalue; a kind of rvalue) doesn't have identity, but is movable. 這些通常都是暫存項目、呼叫函式 (其可依照值傳回資料) 的結果，或是評估任何其他非 glvalue 運算式的結果。These are typically temporaries, the result of calling a function that returns by value, or the result of evaluating any other expression that's not a glvalue,

### rvalue (m)rvalue (m)

rvalue 是可移動。An rvalue is movable. rvalue「參考」 一律會參照 rvalue (假設我們不需要保留其內容的值)。An rvalue reference always refers to an rvalue (a value whose contents it's assumed we don't need to preserve).

``````void foo(A&) { ... }
void foo(A&&) { ... }
void bar(A&& a) // a is a named rvalue reference; it's an lvalue.
{
foo(a); // Calls foo(A&).
foo(static_cast<A&&>(a)); // Calls foo(A&&).
}
A&& get_by_rvalue_ref() { ... } // This unnamed rvalue reference is an xvalue.
``````

## 參考摺疊規則Reference-collapsing rules

• `A& &` 會摺疊成 `A&``A& &` collapses into `A&`.
• `A&& &&` 會摺疊成 `A&&``A&& &&` collapses into `A&&`.

• `A& &&` 會摺疊成 `A&``A& &&` collapses into `A&`.
• `A&& &` 會摺疊成 `A&``A&& &` collapses into `A&`.

## 轉送參考Forwarding references

``````void foo(A&& a) { ... }
``````
• 如我們所見，`A&&` 是 rvalue 參考。`A&&` is an rvalue reference, as we've seen. Const 和 volatile 不適用於 rvalue 參考。Const and volatile don't apply to rvalue references.
• `foo` 只接受類型 A 的 rvalue。`foo` accepts only rvalues of type A.
• rvalue 參考 (例如 `A&&`) 存在的原因，是方便您撰寫針對傳遞暫存項目 (或其他 rvalue) 的情況最佳化的多載。The reason rvalue references (such as `A&&`) exist is so that you can author an overload that's optimized for the case of a temporary (or other rvalue) being passed.
``````template <typename _Ty> void bar(_Ty&& ty) { ... }
``````
• `_Ty&&` 是「轉送參考」 。`_Ty&&` is a forwarding reference. 根據您傳遞至 `bar` 的項目，類型 _Ty 可能是與 volatile/非 volatile 無關的 const/非 const。Depending what you pass to `bar`, type _Ty could be const/non-const independently of volatile/non-volatile.
• `bar` 接受任何類型 _Ty 的 lvalue 或 rvalue。`bar` accepts any lvalue or rvalue of type _Ty.
• 傳遞 lvalue 會導致轉送參考變成 `_Ty& &&`，這會摺疊成 lvalue 參考`_Ty&`Passing an lvalue causes the forwarding reference to become `_Ty& &&`, which collapses to the lvalue reference `_Ty&`.
• 傳遞 rvalue 會導致轉送參考變成 `_Ty&& &&`，這會摺疊成 rvalue 參考`_Ty&&`Passing an rvalue causes the forwarding reference to become `_Ty&& &&`, which collapses to the rvalue reference `_Ty&&`.
• 轉送參考 (例如 `_Ty&&`) 存在的原因「不是」 為了最佳化，而是為了取得您傳遞給它們的項目，以及透明且有效地進行轉送。The reason forwarding references (such as `_Ty&&`) exist is not for optimization, but to take what you pass to them and to forward it on transparently and efficiently. 只有撰寫 (或仔細研究) 程式庫程式碼，才可能遇到轉送參考—例如，在建構函式引數上轉送的 factory 函式。You're likely to encounter a forwarding reference only if you write (or closely study) library code—for example, a factory function that forwards on constructor arguments.

## 來源Sources

• [Stroustrup, 2013] B. Stroustrup:The C++ Programming Language, Fourth Edition.[Stroustrup, 2013] B. Stroustrup: The C++ Programming Language, Fourth Edition. Addison-Wesley.Addison-Wesley. 2013.2013.