Skip to content

fix: correct errors in string literal explanation #237

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 21 additions & 9 deletions book/en-us/03-runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -263,22 +263,34 @@ Temporary variables returned by non-references, temporary variables generated
by operation expressions, original literals, and Lambda expressions
are all pure rvalue values.

Note that a string literal became rvalue in a class, and remains an lvalue in other cases (e.g., in a function):
Note that a literal (except a string literal) is a prvalue. However, a string
literal is an lvalue with type `const char` array. Consider the following examples:

```cpp
class Foo {
const char*&& right = "this is a rvalue";
public:
void bar() {
right = "still rvalue"; // the string literal is a rvalue
}
};
#include <type_traits>

int main() {
const char* const &left = "this is an lvalue"; // the string literal is an lvalue
// Correct. The type of "01234" is const char [6], so it is an lvalue
const char (&left)[6] = "01234";

// Assert success. It is a const char [6] indeed. Note that decltype(expr)
// yields lvalue reference if expr is an lvalue and neither an unparenthesized
// id-expression nor an unparenthesized class member access expression.
static_assert(std::is_same<decltype("01234"), const char(&)[6]>::value, "");

// Error. "01234" is an lvalue, which cannot be referenced by an rvalue reference
// const char (&&right)[6] = "01234";
}
```

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):

```cpp
const char* p = "01234"; // Correct. "01234" is implicitly converted to const char*
const char*&& pr = "01234"; // Correct. "01234" is implicitly converted to const char*, which is a prvalue.
// const char*& pl = "01234"; // Error. There is no type const char* lvalue
```

**xvalue, expiring value** is the concept proposed by C++11 to introduce
rvalue references (so in traditional C++, pure rvalue and rvalue are the same concepts),
a value that is destroyed but can be moved.
Expand Down
28 changes: 19 additions & 9 deletions book/zh-cn/03-runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,22 +224,32 @@ int main() {
要么是求值结果相当于字面量或匿名临时对象,例如 `1+2`。非引用返回的临时变量、运算表达式产生的临时变量、
原始字面量、Lambda 表达式都属于纯右值。

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

```cpp
class Foo {
const char*&& right = "this is a rvalue"; // 此处字符串字面量为右值
public:
void bar() {
right = "still rvalue"; // 此处字符串字面量为右值
}
};
#include <type_traits>

int main() {
const char* const &left = "this is an lvalue"; // 此处字符串字面量为左值
// 正确,"01234" 类型为 const char [6],因此是左值
const char (&left)[6] = "01234";

// 断言正确,确实是 const char [6] 类型,注意 decltype(expr) 在 expr 是左值
// 且非无括号包裹的 id 表达式与类成员表达式时,会返回左值引用
static_assert(std::is_same<decltype("01234"), const char(&)[6]>::value, "");

// 错误,"01234" 是左值,不可被右值引用
// const char (&&right)[6] = "01234";
}
```

但是注意,数组可以被隐式转换成相对应的指针类型,而转换表达式的结果(如果不是左值引用)则一定是个右值(右值引用为将亡值,否则为纯右值)。例如:

```cpp
const char* p = "01234"; // 正确,"01234" 被隐式转换为 const char*
const char*&& pr = "01234"; // 正确,"01234" 被隐式转换为 const char*,该转换的结果是纯右值
// const char*& pl = "01234"; // 错误,此处不存在 const char* 类型的左值
```

**将亡值(xvalue, expiring value)**,是 C++11 为了引入右值引用而提出的概念(因此在传统 C++ 中,
纯右值和右值是同一个概念),也就是即将被销毁、却能够被移动的值。

Expand Down