Skip to content

Commit

Permalink
修正notation相关的翻译
Browse files Browse the repository at this point in the history
  • Loading branch information
adah1972 committed Nov 6, 2022
1 parent 372087a commit 3ebe643
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 49 deletions.
6 changes: 3 additions & 3 deletions 03.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
- **SG2 模块**——主席 Gabriel Dos Reis(微软,之前代表得州农工大学)。
- **SG3 文件系统**——主席 Beman Dawes(“自己”)。
- **SG8 概念**——主席 Andrew Sutton(俄亥俄州阿克伦大学,之前代表得州农工大学)。
- **SG9 范围**——更新 STL,以使用概念,简化表示法,及提供无限序列和管道——主席,Eric Niebler(Facebook)。
- **SG9 范围**——更新 STL,以使用概念,简化写法,及提供无限序列和管道——主席,Eric Niebler(Facebook)。

**SG4 网络**,目前处于休眠状态,因为其结果正在等待被合并到标准([§8.8.1](08.md#881-网络库))中。另一个研究组 **SG11 数据库**,因缺乏共识和缺乏足够数量的志愿者完成工作而解散。

Expand Down Expand Up @@ -149,9 +149,9 @@ ISO 只需要也只认可三名正式官员:

例子:`any``optional``variant` 的不同接口([§8.3](08.md#83-variantoptional-和-any))。概念([§6](06.md#6-概念))。

- **精确规范**:标准是规范,而不是实现。但是,标准是用英语编写的,因此我们做不到数学般的精度。委员会的许多成员擅长数学,但不擅长数学的人更多,因此在规范中没办法使用数学记法。试图使英文文本精确而详尽,则会让文本变得生硬又难以理解。我常常很难理解标准中对我自己提案的描述。
- **精确规范**:标准是规范,而不是实现。但是,标准是用英语编写的,因此我们做不到数学般的精度。委员会的许多成员擅长数学,但不擅长数学的人更多,因此在规范中没办法使用数学式的写法。试图使英文文本精确而详尽,则会让文本变得生硬又难以理解。我常常很难理解标准中对我自己提案的描述。

大多数委员是程序员,而不是设计师,因此规范有时看起来会像程序——用没有类型系统或编译器的低级语言写成的程序。有详尽的如果、那么、否则的说明,却很少写出不变量。更糟糕的是,很多词汇是继承自 C,而且是基于程序源代码文本中的标记,因此,更高级别的概念仅被间接提出。
大多数委员是程序员,而不是设计师,因此规范有时看起来会像程序——用没有类型系统或编译器的低级语言写成的程序。有详尽的如果、那么、否则的说明,却很少写出不变量。更糟糕的是,很多词汇继承自 C,而且是基于程序源代码文本中的标记,因此,更高级别的概念仅被间接提出。

奇怪的是,标准库规范在结构上明显比语言规范更为正式。

Expand Down
24 changes: 12 additions & 12 deletions 04.md
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ void use(vector<int>& v, list<string>& lst)
它最初是由 Thorsten Ottosen(丹麦奥尔堡大学)提出的,理由是“基本上任何现代编程语言都内置了某种形式的 for each” [Ottosen 2005]。我通常不认为“别人都有了”是个好的论据,但在这一情况下,真正的要点是,简单的范围循环可以简化一种最常见的操作,并提供了优化的机会。所以,范围 `for` 完美符合我对 C++ 的总体设计目标。它直接表达应该做什么,而不是详细描述如何做。它的语法简洁,语义明晰。
由于更简单和更明确,范围 `for` 语句消除了一些“微不足道”然而常见的错误:
由于更简单和更明确,范围 `for` 的写法消除了一些“微不足道”然而常见的错误:
```cpp
void use(vector<int>& v, list<string>& lst)
Expand Down Expand Up @@ -523,7 +523,7 @@ void use(const Matrix& m1, const Matrix& m2)
}
```
这里 `operator+` 让我们可以使用常规的数学记法,同时也是一个工厂函数返回大对象的示例。
这里 `operator+` 让我们可以使用常规的数学写法,同时也是一个工厂函数返回大对象的示例。
通过 `const` 引用把 `Matrix` 传递给函数,一直是传统而高效的做法。而问题在于,如何以传值来返回 `Matrix` 而不用拷贝所有的元素。早在 1982 年,我曾通过一种优化方案来部分解决这一问题,即干脆将返回值分配在调用函数的栈帧上。它工作得很好,但它只是优化技术,不能处理更复杂的返回语句。而用户在按值返回“大对象”时,需要确保绝不会进行大量的数据复制。
Expand All @@ -543,9 +543,9 @@ public:
};
```

当用于初始化或赋值的源对象马上就会被销毁时,**移动**就比**拷贝**要更好:移动操作只是简单地把对象的内部表示“窃取”过来。`&&` 表示构造函数是一个**移动构造函数**`Matrix&&` 被称为**右值引用**。当用于模板参数时,右值引用的符号 `&&` 被叫做**转发引用**,这是由 John Spicer 在 2002 年的一次会议上,同 Dave Abrahams 和 Howard Hinnant 一起提出的。
当用于初始化或赋值的源对象马上就会被销毁时,**移动**就比**拷贝**要更好:移动操作只是简单地把对象的内部表示“窃取”过来。`&&` 表示构造函数是一个**移动构造函数**`Matrix&&` 被称为**右值引用**。当用于模板参数时,右值引用的写法 `&&` 被叫做**转发引用**,这是由 John Spicer 在 2002 年的一次会议上,同 Dave Abrahams 和 Howard Hinnant 一起提出的。

这个 `Matrix` 的例子有个有意思的地方:如果 `Matrix` 的加法返回指针的话,那传统的数学记号`a+b`)就不能用了。
这个 `Matrix` 的例子有个有意思的地方:如果 `Matrix` 的加法返回指针的话,那传统的数学写法`a+b`)就不能用了。

移动语义蕴含着性能上的重大好处:它消除了代价高昂的临时变量。例如:

Expand Down Expand Up @@ -701,7 +701,7 @@ vector<int> v = {7,8}; // 应该可以工作(显然,但是没有)
上一个例子令我非常不舒服,因为它违反了 C++ 的根本设计目标,即为内建类型和用户定义的类型提供同等的支持。特别是,因为对数组初始化有比 `vector` 更好的支持,这会鼓励人们使用容易出错的内建数组。
当 C++0x 的工作从 2002 年开始的时候,Daniel Gutson、Francis Glassborow、Alisdair Meredith、Bjarne Stroustrup 和 Gabriel Dos Reis 曾进行了许多讨论和提议,来解决其中一些问题。在 2005 年,Gabriel Dos Reis 和我提出了**统一初始化**的写法,该写法可用于每种类型,并且在程序中的任何地方都具有相同的含义 [Stroustrup and Dos Reis 2005b]。这种写法有望大大简化用户代码并消除许多不易察觉的错误。该表示法是基于使用花括号的列表写法。举例来说:
当 C++0x 的工作从 2002 年开始的时候,Daniel Gutson、Francis Glassborow、Alisdair Meredith、Bjarne Stroustrup 和 Gabriel Dos Reis 曾进行了许多讨论和提议,来解决其中一些问题。在 2005 年,Gabriel Dos Reis 和我提出了**统一初始化**的写法,该写法可用于每种类型,并且在程序中的任何地方都具有相同的含义 [Stroustrup and Dos Reis 2005b]。这种写法有望大大简化用户代码并消除许多不易察觉的错误。这一写法基于使用花括号的列表写法。举例来说:
```cpp
int a = {5}; // 内建类型
Expand Down Expand Up @@ -730,7 +730,7 @@ template<typename T> int foo(T);
int z = foo(X{1}); // 显式构造
```
其中许多的情形,例如为使用 `new` 创建的对象提供初始化器列表,干脆就没法使用以前的方式来完成
其中许多的情形,例如为使用 `new` 创建的对象提供初始化器列表,使用以前的写法根本就做不到
可惜,对于这一理想,我们仅仅达到不完全的近似,我们有的方案只能算大致统一。有些人发现,使用 `{…}` 很别扭,除非 `…` 是同质对象的列表,而其他人则坚持 C 语言中对聚合和非聚合的区分,并且许多人担心没有显式类型标记的列表会导致歧义和错误。例如,以下写法被认为是危险的,不过最终还是被接受了:
Expand Down Expand Up @@ -794,7 +794,7 @@ public:
vector<int> v3 {1,2,3,4,5}; // 具有 5 个元素的 vector
```
令人遗憾的是,统一初始化(`{}`——初始化)的使用并不像我期望的那样广泛。人们似乎更喜欢熟悉的写法和熟悉的缺陷。我似乎陷入了 N+1 问题:你有 N 个不兼容和不完整的解决方案,因此添加了一个新的更好的解决方案。不幸的是,原始的 N 个解决方案并没有消失,所以你现在有了 N+1 个解决方案。公平地说,有一些细微的问题超出了本文的范围,这些问题只是在 C++14、C++17 和 C++20 中被逐步补救。我的印象是,泛型编程和对更简洁的表示法的推进正在慢慢增加统一初始化的吸引力。所有标准库容器(如 `vector`)都有初始化器列表构造函数。
令人遗憾的是,统一初始化(`{}`——初始化)的使用并不像我期望的那样广泛。人们似乎更喜欢熟悉的写法和熟悉的缺陷。我似乎陷入了 N+1 问题:你有 N 个不兼容和不完整的解决方案,因此添加了一个新的更好的解决方案。不幸的是,原始的 N 个解决方案并没有消失,所以你现在有了 N+1 个解决方案。公平地说,有一些细微的问题超出了本文的范围,这些问题只是在 C++14、C++17 和 C++20 中被逐步补救。我的印象是,泛型编程和对更简洁写法的普遍推动正在慢慢增加统一初始化的吸引力。所有标准库容器(如 `vector`)都有初始化器列表构造函数。
### 4.2.6 `nullptr`
Expand Down Expand Up @@ -895,7 +895,7 @@ void f(int x)

与其他问题相比,这似乎并不重要,所以几十年来什么都没有发生。2006 年的一天,David Vandevoorde(EDG)、Mike Wong(IBM)和我在柏林的一家中餐馆吃了一顿丰盛的晚餐。我们在餐桌边聊起了天,于是一个设计浮现在一张餐巾纸上。这个讨论的起因是 IBM 的一项十进制浮点提案中对后缀的需求,该提案最终成了一个独立的国际标准 [Klarer 2007]。在大改后,该设计在 2008 年成为**用户定义字面量**(通常称为 UDL)[McIntosh et al. 2008]。当时让 UDL 变得有趣的重要发展是 `constexpr` 提案的进展([§4.2.7](#427-constexpr-函数))。有了它,我们可以保证编译期求值。

照例,找到一种可接受的写法是一个问题。我们决定使用晦涩的 `operator""` 作为字面量运算符(literal operator)的写法是可以接受的,毕竟 `""` 是一个字面量。然后,`""x` 是后面跟着后缀 `x` 的字面量。这样一来,要定义一个用于 `complex` 数的 `Imaginary` 类型,我们可以定义:
照例,找到一种可接受的写法是一个问题。我们决定使用晦涩的 `operator""` 作为字面量运算符(literal operator)的写法是可以接受的,毕竟 `""` 是一个字面量。然后,`""x` 是用来表示字面量后面跟后缀 `x` 的写法。这样一来,要定义一个用于 `complex` 数的 `Imaginary` 类型,我们可以定义:

```cpp
constexpr Imaginary operator""i(long double x) { return Imaginary(x); }
Expand Down Expand Up @@ -1104,7 +1104,7 @@ sort(v.begin(),v.end(),[](int x, int y) { return x>y; });
> - 不能实例化包含任意长度参数列表的类模板和函数模板。
> - 不能以类型安全的方式传递任意个参数给某个函数

这些都是重要目标,但我起初发现其解决方案过于复杂,记法太过晦涩,按我的品味其编程风格又太递归。不过在 Douglas Gregor 于 2004 年做的精彩演示之后,我改变了主意并全力支持这项提案,帮助它在委员会顺利通过。我被说服的部分原因是变参模板和当时的变通方案在编译时间上的对比测量。编译时间过长的问题随模板元编程的大量使用([§10.5.2](10.md#1052-元编程))变得越来越严重,对此变参模板是一项重大(有时是 20 倍)改进。可惜,变参模板越变越流行,也成了 C++ 标准库中必需的部分,以至编译时间的问题又出现了。不过,成功的惩罚(在当时)还是在遥远的将来。
这些都是重要目标,但我起初发现其解决方案过于复杂,写法太过晦涩,按我的品味其编程风格又太递归。不过在 Douglas Gregor 于 2004 年做的精彩演示之后,我改变了主意并全力支持这项提案,帮助它在委员会顺利通过。我被说服的部分原因是变参模板和当时的变通方案在编译时间上的对比测量。编译时间过长的问题随模板元编程的大量使用([§10.5.2](10.md#1052-元编程))变得越来越严重,对此变参模板是一项重大(有时是 20 倍)改进。可惜,变参模板越变越流行,也成了 C++ 标准库中必需的部分,以至编译时间的问题又出现了。不过,成功的惩罚(在当时)还是在遥远的将来。

变参模板的基本思路是,递归构造一个**参数包**,然后在另一个递归过程来使用它。递归技巧是必须的,因为参数包中的每个元素都有它自己的类型(和大小)。

Expand Down Expand Up @@ -1173,15 +1173,15 @@ template<typename T> using Vec = MyVector<T, MyAlloc<T> >;
其中的 `using` 语法,即要引入的名字总是出现在前面,则是我的建议。
我和 Gabriel Dos Reis 一道把这个特性推广成一个(几乎)完整的别名机制,并最终得到接受 [Stroustrup and Dos Reis 2003c]。即便不涉及模板,它也给了人们一种记法上的选择
我和 Gabriel Dos Reis 一道把这个特性推广成一个(几乎)完整的别名机制,并最终得到接受 [Stroustrup and Dos Reis 2003c]。即便不涉及模板,它也给了人们一种写法上的选择
```cpp
typedef double (*analysis_fp)(const vector<Student_info>&);
using analysis_fp = double (*)(const vector<Student_info>&);
```

类型和模板别名是某些最有效的零开销抽象及模块化技巧的关键。别名让用户能够使用一套标准的名字而同时让各种实现使用各自(不同)的实现技巧和名字。这样就可以在拥有零开销抽象的同时保持方便的用户接口。考虑某通讯库(使用了 Concepts TS [Sutton 2017] 和 C++20 的简化记法)中的一个实例:
类型和模板别名是某些最有效的零开销抽象及模块化技巧的关键。别名让用户能够使用一套标准的名字而同时让各种实现使用各自(不同)的实现技巧和名字。这样就可以在拥有零开销抽象的同时保持方便的用户接口。考虑某通讯库(利用了 Concepts TS [Sutton 2017] 和 C++20 的写法简化)中的一个实例:

```cpp
template<InputTransport Transport, MessageDecoder MessageAdapter>
Expand Down Expand Up @@ -1269,7 +1269,7 @@ void use()
}
```

进一步的记法简化被提议加入 C++20 [Spertus 2018],但没来得及成功通过:
进一步的写法简化被提议加入 C++20 [Spertus 2018],但没来得及成功通过:

```cpp
tuple SVD(const Matrix& A) // 从返回语句中推导出元组模板参数
Expand Down
6 changes: 3 additions & 3 deletions 05.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ auto a = 1'234'567; // 1234567(整数)
auto b = 1'234'567s; // 1234567 秒
```

尽管有严厉的警告指出使用单引号会破坏无数的工具,但实际效果似乎不错。单引号由 David Vandevoorde 提出 [Crowl et al. 2013]。他指出,在一些国家,特别是在瑞士的金融符号中,单引号被当作分隔符来使用。
尽管有严厉的警告指出使用单引号会破坏无数的工具,但实际效果似乎不错。单引号由 David Vandevoorde 提出 [Crowl et al. 2013]。他指出,在一些国家,特别是在瑞士的金融写法中,单引号被当作分隔符来使用。

我的另一个建议,使用空白字符,则一直没有得到认同:

Expand Down Expand Up @@ -119,9 +119,9 @@ Java 1.8 (~2013): x -> x * x;
D 2.0 (~2009): (x) { return x * x; };
```
我认为,使用 `auto` 而且没有为 lambda 表达式引入特殊的不与函数共享的记法是正确的。此外,我认为在 C++14 中引入泛型 lambda 表达式,而没有引入概念,则是个错误;这样一来,对受约束和不受约束的 lambda 表达式参数和函数参数的规则和记法就没有一起考虑。由此产生的语言技术上的不规则(最终)在 C++20 中得到了补救([§6.4](06.md#64-c20-概念))。但是,我们现在有一代程序员习惯于使用不受约束的泛型 lambda 表达式并为此感到自豪,而克服这一点将花费大量时间。
我认为,使用 `auto` 而且没有为 lambda 表达式引入特殊的不与函数共享的写法是正确的。此外,我认为在 C++14 中引入泛型 lambda 表达式,而没有引入概念,则是个错误;这样一来,对受约束和不受约束的 lambda 表达式参数和函数参数的规则和写法就没有一起考虑。由此产生的语言技术上的不规则(最终)在 C++20 中得到了补救([§6.4](06.md#64-c20-概念))。但是,我们现在有一代程序员习惯于使用不受约束的泛型 lambda 表达式并为此感到自豪,而克服这一点将花费大量时间。
从这里简短的讨论来看,似乎委员会流程对记法/语法给予了特大号的重视。可能是这样,但是语法并非无足轻重。语法是程序员的用户界面,与语法有关的争论通常反映了语义上的分歧,或者反映了对某一特性的预期用途。记法应反映基础的语义,而语法通常偏向于对某种用法(而非其他用法)有利。例如,一个完全通用和啰嗦的记法有利于希望表达细微差别的专家,而一个为表达简单情况而优化的记法,则有利于新手和普通用户。我通常站在后者这边,并且常常赞成两者同时都提供([§4.2](04.md#42-c11简化使用))。
从这里简短的讨论来看,似乎委员会流程对写法/语法给予了特大号的重视。可能是这样,但是语法并非无足轻重。语法是程序员的用户界面,与语法有关的争论通常反映了语义上的分歧,或者反映了对某一特性的预期用途。写法应反映基础的语义,而语法通常偏向于对某种用法(而非其他用法)有利。例如,一个完全通用和啰嗦的写法有利于希望表达细微差别的专家,而一个为表达简单情况而优化的写法,则有利于新手和普通用户。我通常站在后者这边,并且常常赞成两者同时都提供([§4.2](04.md#42-c11简化使用))。
## 5.5 `constexpr` 函数中的局部变量
Expand Down
Loading

0 comments on commit 3ebe643

Please sign in to comment.