Skip to content

Commit 41b88c8

Browse files
book: redo string literal explanation (changkun#237)
1 parent 25a8fd2 commit 41b88c8

File tree

2 files changed

+40
-18
lines changed

2 files changed

+40
-18
lines changed

book/en-us/03-runtime.md

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -263,22 +263,34 @@ Temporary variables returned by non-references, temporary variables generated
263263
by operation expressions, original literals, and Lambda expressions
264264
are all pure rvalue values.
265265
266-
Note that a string literal became rvalue in a class, and remains an lvalue in other cases (e.g., in a function):
266+
Note that a literal (except a string literal) is a prvalue. However, a string
267+
literal is an lvalue with type `const char` array. Consider the following examples:
267268
268269
```cpp
269-
class Foo {
270-
const char*&& right = "this is a rvalue";
271-
public:
272-
void bar() {
273-
right = "still rvalue"; // the string literal is a rvalue
274-
}
275-
};
270+
#include <type_traits>
276271
277272
int main() {
278-
const char* const &left = "this is an lvalue"; // the string literal is an lvalue
273+
// Correct. The type of "01234" is const char [6], so it is an lvalue
274+
const char (&left)[6] = "01234";
275+
276+
// Assert success. It is a const char [6] indeed. Note that decltype(expr)
277+
// yields lvalue reference if expr is an lvalue and neither an unparenthesized
278+
// id-expression nor an unparenthesized class member access expression.
279+
static_assert(std::is_same<decltype("01234"), const char(&)[6]>::value, "");
280+
281+
// Error. "01234" is an lvalue, which cannot be referenced by an rvalue reference
282+
// const char (&&right)[6] = "01234";
279283
}
280284
```
281285

286+
However, an array can be implicitly converted to a corresponding pointer.The result, if not an lvalue reference, is an rvalue (xvalue if the result is an rvalue reference, prvalue otherwise):
287+
288+
```cpp
289+
const char* p = "01234"; // Correct. "01234" is implicitly converted to const char*
290+
const char*&& pr = "01234"; // Correct. "01234" is implicitly converted to const char*, which is a prvalue.
291+
// const char*& pl = "01234"; // Error. There is no type const char* lvalue
292+
```
293+
282294
**xvalue, expiring value** is the concept proposed by C++11 to introduce
283295
rvalue references (so in traditional C++, pure rvalue and rvalue are the same concepts),
284296
a value that is destroyed but can be moved.

book/zh-cn/03-runtime.md

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -224,22 +224,32 @@ int main() {
224224
要么是求值结果相当于字面量或匿名临时对象,例如 `1+2`。非引用返回的临时变量、运算表达式产生的临时变量、
225225
原始字面量、Lambda 表达式都属于纯右值。
226226

227-
需要注意的是,字符串字面量只有在类中才是右值,当其位于普通函数中是左值。例如:
227+
需要注意的是,字面量除了字符串字面量以外,均为纯右值。而字符串字面量是一个左值,类型为 `const char` 数组。例如:
228228

229229
```cpp
230-
class Foo {
231-
const char*&& right = "this is a rvalue"; // 此处字符串字面量为右值
232-
public:
233-
void bar() {
234-
right = "still rvalue"; // 此处字符串字面量为右值
235-
}
236-
};
230+
#include <type_traits>
237231

238232
int main() {
239-
const char* const &left = "this is an lvalue"; // 此处字符串字面量为左值
233+
// 正确,"01234" 类型为 const char [6],因此是左值
234+
const char (&left)[6] = "01234";
235+
236+
// 断言正确,确实是 const char [6] 类型,注意 decltype(expr) 在 expr 是左值
237+
// 且非无括号包裹的 id 表达式与类成员表达式时,会返回左值引用
238+
static_assert(std::is_same<decltype("01234"), const char(&)[6]>::value, "");
239+
240+
// 错误,"01234" 是左值,不可被右值引用
241+
// const char (&&right)[6] = "01234";
240242
}
241243
```
242244

245+
但是注意,数组可以被隐式转换成相对应的指针类型,而转换表达式的结果(如果不是左值引用)则一定是个右值(右值引用为将亡值,否则为纯右值)。例如:
246+
247+
```cpp
248+
const char* p = "01234"; // 正确,"01234" 被隐式转换为 const char*
249+
const char*&& pr = "01234"; // 正确,"01234" 被隐式转换为 const char*,该转换的结果是纯右值
250+
// const char*& pl = "01234"; // 错误,此处不存在 const char* 类型的左值
251+
```
252+
243253
**将亡值(xvalue, expiring value)**,是 C++11 为了引入右值引用而提出的概念(因此在传统 C++ 中,
244254
纯右值和右值是同一个概念),也就是即将被销毁、却能够被移动的值。
245255

0 commit comments

Comments
 (0)