编辑信息

常见问题编辑指南

谁应该阅读此文……以及为何

谁:C++ 常见问题编辑者应阅读此文。

为何:它提供了正确更新常见问题的基本要素。

风格(请勿跳过此部分)

常见问题中有很多问题:C++11 之前的建议,模板元编程(TMP)方面薄弱等等。请大力修复这些问题。

但请不要“修复”那种随性、有趣、精炼的写作风格;那种写作风格没有问题。常见问题使用得体但生动的语言,常常一针见血,鲜少无聊。读者喜欢这种风格;一些作者不喜欢。我们内心深处的极客希望保持语气中立、平淡、严肃。相反,常见问题读起来很有趣。读者实际上很享受阅读。这让他们持续阅读,最终更好地理解 C++。他们玩得开心,要么继续阅读,要么稍后回来,或者两者兼而有之。请不要“修复”这种风格;二十多年来,它已对成千上万的读者证明了其有效性。这种风格没有问题。

没有问题的例子:开场白。 常见问题的答案以开场白开始:一句不完整,有时滑稽,偶尔离谱,且常常不精确或不准确,或两者兼而有之的陈述。开场白不是提供详尽、准确、完整的答案,包含所有“如果”、“而且”和“但是”的地方——那才是常见问题其余部分的作用。开场白是为了吸引注意力;它吊人胃口,引诱读者进入真正的答案。它是“滋滋声”,而不是“牛排”。请不要试图使其“完整”或“准确”。

没有问题的例子:“Xyzzy 是邪恶的”这种说法。 常见问题有意在使用技术结构时采用“邪恶”或“正义”等夸张的说法。这是玩乐主题的一部分,它使常见问题变得愉快和引人入胜,读者会因为享受这种体验而阅读更多、学习更多。所以请不要通过删除“邪恶”一词来“修复”它。也不要过于拘泥于要求对特定结构何时是邪恶、何时是正义进行超精确和技术上可辩护的定义:一个邪恶的结构不是绝不应该使用的——它只是一个通常应该避免的结构,除非它是其他邪恶中较小的那一个,是替代方案中最不坏的那个。甚至还有一个常见问题解释了常见问题对该术语的使用。这是一种轻松幽默的说法,对读者有益。请不要删除它。

“总是”/“从不”,“倾向于”/“避免”和“考虑”。 我们承认几乎所有的指导方针都有例外。请注意,即使被标记为“邪恶”的构造也不是“永不使用 Xyz”的规则;常见问题指出,当邪恶构造是其他邪恶中较小的那一个时,它们是合适的。考虑到这一点,在指导方针中(遵循《C++ 编码标准》)优先使用这些词语:“总是”和“从不”意味着“这应该默认地(或不)从你的指尖流出”,除非在极少数情况下;“倾向于”和“避免”意味着“通常正确(或错误),但要注意一些常见的例外”,你可能会有不同的做法;而“考虑”意味着“这是一种在特定情况下可能很有用的技术”。

总结: 常见问题需要大量的技术更改。很多。但读者喜欢其活泼、有趣的阅读风格——这种风格自1991年以来一直得到验证。作为作者,请享受乐趣,这样你的读者也会享受乐趣。这将使他们持续阅读,最终使他们学习更多的 C++。所以,把你的臭脚搭在凌乱的桌子上,放松身心,让常见问题保持活力。

每个常见问题和章节的 ID

每个常见问题和章节都有一个在整个常见问题中全局唯一且不可变的 ID。这些 ID 用于(许多!)内部交叉引用。

在下面的示例中,章节的 ID 是 ctors,这也是(按设计!)其 URL 的基本名称:http://www.isocpp.org/wiki/faq/ctors。常见问题的 ID 是 init-lists

## 构造函数 {#ctors} … ### 我的构造函数应该使用“初始化列表”还是“赋值”?{#init-lists} …


使用 ID 的关键

  • ID 是全局唯一的。 章节和常见问题的 ID 合并到一个单一的命名空间中,因此“全局唯一”的要求意味着不能有任何其他章节常见问题具有 ID ctors,同样也不能有任何其他章节常见问题具有 ID init-lists
  • ID 是不可变的。 章节和常见问题的 ID 是不可变的:一旦发布,它们绝不能更改。章节(人类可读的)标题可以更改,但其 ID(一旦发布)绝不能更改。同样,常见问题(人类可读的)问题和答案可以更改,但其 ID(一旦发布)绝不能更改。
  • 常见问题 ID 命名的是常见问题的主题,而不是其位置。 除非给定常见问题绑定到特定章节,否则请抵制使用章节 ID 作为常见问题 ID 前缀的诱惑。常见问题的 ID 应该让编辑者知道它是什么,而不是它在哪里(因为它可能,而且通常会,被重新定位到不同的章节)。例如,有一个常见问题描述了“巧妙计数习语”(Nifty Counter Idiom),它(截至本文撰写时)恰好位于名为“构造函数”(ID ctors)的章节中,但是“巧妙计数习语”的 ID 是 nifty-counter-idiom,而不是 ctors-nifty-counter-idiom
  • ID 用作链接目标。 所有所有章节和常见问题的链接的 Markdown 语法必须始终使用目标的 ID,而不是其 URL。生成 HTML 的机制将这些 ID 转换为真实的 URL,并提供解决这些 URL 的方法,即使目标已移动。换句话说,就是永久链接。

这里的宏观目标是实现目录的可塑性。常见问题是一个活文档;其整体组织将随时间而变化。为了提高常见问题对读者的实用性,常见问题编辑者将随着时间的推移添加新的常见问题,在章节内重新排序常见问题,将常见问题从一个章节移动到另一个章节,重新排序章节,拆分章节,以及创建新章节。由于 ID 和所有围绕 ID 的其他机制,所有这些更改都可以在不担心链接失效的情况下进行。所有链接,甚至“深层”链接,都是永久链接

ID 很好。

为孩子们使用它们。

常见问题-Markdown 基础

C++ 常见问题使用 Markdown 的一个变体(Markdown 和 SmartyPants 联合子集的超集)。本节解释编辑常见问题时需要了解的基础知识。

普通文本会自动流入段落。要开始新段落,请用空行将其与前面的文本隔开。
当您想要…… 您输入…… 读者看到…… 讨论
使用 Markdown,而不是 HTML
这里推荐使用 Markdown!
这里推荐使用 Markdown!
FAQ-Markdown 允许嵌入 HTML,但这应该非常罕见。
FAQ 本身目前(2013 年 9 月)是 99.999% Markdown 和 0.001% HTML。
谁知道这个比例是否会有些变化,但 HTML 应该保持稀有。
段落
相邻行流入一个段落。空行开始一个新段落。

相邻行流入一个段落。

空行开始一个新段落。

花式双引号
这样
待办:使用 JS 注入“
像“这样”
它们在 `code-span`~~~~code-block~~~~ 中不会被卷曲化
花式单引号
就像 这样,‘是吗?
待办:使用 JS 注入 ‘
就像‘这样’,‘是吗?
`code-span`~~~~code-block~~~~ 中不进行卷曲化
连字符
像 - 这样。
像 - 这样。
“en”破折号
像 – 这样。
像 – 这样。
“em”破折号
像 — 这样。
像 — 这样。
粗体
像 **这样**
这样
使用 **这样**
而不是 __这样__
原因:与常见问题解答的其余部分保持一致
斜体
像 *这样*
这样
使用 *这样*
而不是 _这样_
原因:与常见问题解答的其余部分保持一致
代码片段
像 `std::cout << 42`
std::cout << 42

代码片段保留水平空白。

代码片段引用大多数 Markdown 元字符:* 等。

链接到常见问题的一个章节
像 [这样][ctors]
(目标 = ID ctors
这样
链接到章节时
使用目标的 ID
而不是目标的 URL,原因:详情请参阅此处
链接到单个常见问题
像 [这样][init-lists]
(目标 = ID init-lists
这样
链接到常见问题时
使用目标的 ID
而不是目标的 URL,原因:详情请参阅此处
链接到外部网页
像 [这样](https://boost.ac.cn)
(目标 = URL https://boost.ac.cn
这样
链接到外部网页时:使用目标的 URL
几个链接到
同一个外部网页
像 [这样][42]。……还有 [这个][42]。…… [42]: https://boost.ac.cn
(目标 = [42]: … 中的 URL)

这样
  …
还有 这个
  …

这些自制 ID 是本地/作用域内的章节。

这些自制 ID 请使用数字
(不会与 FAQ/章节 ID 冲突)。

无序列表
Lorem ipsum + Dolor sit amet. + Sed do eiusmod tempor. + Dolore magna aliqua. Ut enim ad minim veniam.
(那是空格“+”空格)

Lorem ipsum

  • Dolor sit amet。
  • Sed do eiusmod tempor。
  • Dolore magna aliqua。

Ut enim ad minim veniam。

使用  + …
而不是  * …
原因:与常见问题解答的其余部分保持一致
有序列表
Lorem ipsum 1. Dolor sit amet. 1. Sed do eiusmod tempor. 1. Dolore magna aliqua. Ut enim ad minim veniam.
(那是空格“1.”空格)

Lorem ipsum

  1. Dolor sit amet。
  2. Sed do eiusmod tempor。
  3. Dolore magna aliqua。

Ut enim ad minim veniam。

使用 1. … 1. … 1. …
而不是 1. … 2. … 3. …
原因:减少繁琐,消除手动重新编号
列表中的列表
Lorem ipsum + Dolor sit amet + Consectetur + Adipisicing + Elit + Sed do eiusmod tempor + Incididunt + Ut + Labore + Dolore magna aliqua. Ut enim ad minim veniam.

Lorem ipsum

  • Dolor sit amet
    • Consectetur
    • Adipisicing
    • Elit
  • Sed do eiusmod tempor
    • Incididunt
    • Ut
    • Labore
  • Dolore magna aliqua。

Ut enim ad minim veniam。

嵌套{无序、有序}列表
……嵌套在{无序、有序}列表内
……到任何嵌套级别。
缩进
Lorem ipsum > dolor sit > amet. Consectetur adipisicing elit
(那是空格“>”空格)

Lorem ipsum

dolor sit amet。

Consectetur adipisicing elit

使用  > > … 进行双重缩进。
使用  > + … 缩进项目符号列表。
使用  > 1. … 缩进有序列表。
使用  > ~~~~ 缩进代码块。
使用  > | … | 缩进表格。
代码块
~~~~ void f(int n) { // code is prettified std::cout << “n = ” << n << std::endl; } ~~~~
void f(int n)
{
  // code is prettified
  std::cout << "n = " << n
            << std::endl;
}

代码块保留空白。

代码块引用大多数 Markdown 元字符:* 等。

表格
| 函数 | 描述 | | -‌-‌-‌-‌-‌-‌-‌-‌- | -‌-‌-‌-‌-‌-‌-‌-‌-‌-‌-‌-‌-‌-‌- | | `help()` | 显示帮助信息 | | `crash()` | *崩溃矩阵!* |
函数 描述
帮助() 显示帮助信息
崩溃() 崩溃矩阵!

在表格单元格内使用 <br> 添加换行符。

使用(可选的)前导/尾随 |
原因:与常见问题解答的其余部分保持一致。

您不需要将 | 对齐。

有关 +*>|~` 等元字符的规则,请参阅下文

创建新章节/常见问题及/或重新排序

“结构性”更改是指影响整体目录的更改。这意味着新的章节/常见问题、章节/常见问题的标题,或章节/常见问题的顺序。

创建新章节

每个章节都是一个网页,以单个连续的 Markdown 文件实现,并具有以下形式

## 章节标题在此 {#chapter-id-在此} /*…常见问题在此…*/ {embed=”id-defns”}

章节的 ID(如上所示为 chapter-id-goes-here):(1) 必须以小写 a-z 开头,后跟可选的小写 a-z、数字 0-9 和/或连字符;例如,abcs 而不是 ABCsinput-output 而不是 input_outputbig3。(2) 不可变:一旦发布,章节的 ID 绝不能更改;其文本标题可以更改,但其 ID 不能。(3) 必须全局唯一:任何章节 ID 都不能与任何其他章节或任何常见问题的 ID 相同。(4) 必须与 URL 的基本名称部分匹配,例如,ID input-output 必须与 URL http://www.isocpp.org/wiki/faq/input-output 对应。

在页面发布之前,一位管理员必须将新创建的章节添加到神奇的 id-defns 文件中。它也必须添加到主索引页中。

创建新常见问题

每个常见问题都包含在一个章节中,是该章节 Markdown 文件的一部分,并具有以下形式

### 问题在这里?{#faq-id-在这里} 精炼的开场白在这里… 常见问题的主体在这里…

常见问题的 ID(如上所示为 faq-id-goes-here):(1) 必须以小写 a-z 开头,后跟可选的小写 a-z、数字 0-9 和/或连字符;例如,nan 而不是 NaNconst-cast 而不是 const_cast 等。(2) 不可变:一旦发布,常见问题的 ID 绝不能更改;其文本标题/问题可以更改,但其 ID 不能。(3) 必须全局唯一:任何常见问题的 ID 都不能与任何其他常见问题或任何章节的 ID 相同。

在页面发布之前,一位管理员必须将新创建的常见问题添加到神奇的 id-defns 文件中。

详细答案是您阐述精炼的开场白的地方。如果“如果”、“而且”和“但是”足够多,以至于使开场白产生误导,通常最好让开场白保持误导性,但以一个自白开始主体,例如:“那是一个过度简化;请继续阅读以了解真实情况。”目的是激励他们努力阅读复杂的细节。

通常情况下,如果您先处理常见情况,然后再添加边缘情况,会更具可读性和易于理解。

重新排序章节

要重新排序现有章节,只需更改它们在主索引文件中出现的顺序即可。

重新排序常见问题

要重新排序同一章节中的现有常见问题,只需编辑该章节并移动它们。

要将常见问题从一个章节移动到另一个章节,请将该常见问题移动到新的章节文件,然后请管理员修改神奇的 id-defns 文件

修改章节标题

打开章节,点击编辑,修改章节标题的人类可读文本(在下面的示例中为“类和对象”),然后请管理员修改神奇的 id-defns 文件

摘自 http://www.isocpp.org/wiki/faq/classes-and-objects
## 类和对象 {#classes-and-objects} /*…等等等等…*/

章节标题允许包含行内 Markdown,如 `code-spans`*italics* 等,并且可以跨越 Markdown 输入的多个物理行。它不能包含链接,也不能包含代码块、有序/无序列表等块级元素。

提醒:章节标题是可变的,但章节 ID(在上述示例中为 classes-and-objects)不可变。一旦发布,ID 绝不能更改。

修改常见问题标题/问题

打开章节,点击编辑,修改常见问题标题(在下面的示例中为“类和对象”)的人类可读文本,然后请管理员修改神奇的 id-defns 文件

摘自 http://www.isocpp.org/wiki/faq/inline-functions
/*…等等等等…*/ ### `inline` 函数能提高性能吗?{#inline-and-perf} 能,也不能。有时可以。也许吧。没有简单的答案。`inline` 函数可能会使代码更快,它们也可能/*…等等等等…*/

常见问题标题/问题允许包含行内 Markdown,如 `code-spans`*italics* 等,并且可以跨越 Markdown 输入的多个物理行。它不能包含链接,也不能包含代码块、有序/无序列表等块级元素。

提醒:常见问题标题/问题是可变的,但常见问题 ID(在上述示例中为 inline-and-perf)不可变。一旦发布,ID 绝不能更改。

显示元字符

常见问题的 Markdown 变体和 SmartyPants 有许多元字符。不幸的是,其中一些在 C++ 代码中很常见;请小心。

下表解释了哪些元字符在 `code-span` 中会自动引用,以及将其显示为文字的首选解决方法。

例如,如果您输入 ptr = &reg;,它显示为 ptr = ®(& 是一个元字符),如果您输入 f<int>(),它显示为 f()(<int> 在语法上类似于 HTML 元素);但是这些都可以通过 `code-span` 修复。

元字符 可能变成…… 当出现在 `` 外部并且当…… 首选的解决方法
& HTML 实体 当后面跟着字母或 # 使用反引号:`&`
在 & 后添加空格
HTML 实体语法:&amp;
代码块:~~~~~~~~
(注意:不要转义它:AT\&T → AT\&T)
<>
(成对)
HTML 元素 < 后面没有空格时
> 前面没有空格时
使用反引号:`<...>`
在 < 后和 > 前添加空格(证明:< br >)
HTML 实体语法:&lt;&gt;
代码块:~~~~~~~~
(注意:不要转义它:\<br\> → \<br>)
>
(单独)
块引用 当它是行上第一个非空白字符时 转义它:\> → >
使用反引号:`>`
用空格包围:" > " (证明:< br >)
HTML 实体语法:&gt;
代码块:~~~~~~~~
\ “转义”前缀 当后面跟着元字符如 * 转义它:\\ → \
使用反引号:`\`
在 \ 后添加一个空格
HTML 实体语法:&92;
代码块:~~~~~~~~
[] 链接 当它在其他方括号内时:[[]]
紧跟括号时:[]()
例如,operator new[](size_t) → operator new
转义它:\[\[foo\]\] → [[foo]]
使用反引号:`[``]`
添加空格:[ [] ] [] ()
HTML 实体语法:&#91;&#93;
代码块:~~~~~~~~
__
(下划线)
斜体 当同一段落中有两个时
例如,_foo + bar_foo + bar
转义它:\_xyz\_ → _xyz_
使用反引号:`_`
用空格包围:" _ " (证明:_ x _ )
HTML 实体语法:&#95;
代码块:~~~~~~~~
**
(成对)
斜体 当同一段落中有两个时
例如,foo*bar*baz → foobarbaz
转义它:\*xyz\* → *xyz*
使用反引号:`*`
用空格包围:" * "
    (但不能在行首!)
HTML 实体语法:&#42;
代码块:~~~~~~~~
*
(单独)
项目符号列表 当它是行上第一个非空白字符时
前面是空行或项目符号列表
转义它:\* → *
使用反引号:`*`
HTML 实体语法:&#42;
代码块:~~~~~~~~
+ 项目符号列表 当它是行上第一个非空白字符时
前面是空行或项目符号列表
转义它:\+ → +
使用反引号:`+`
HTML 实体语法:&#43;
代码块:~~~~~~~~
- 项目符号列表 当它是行上第一个非空白字符时
前面是空行或项目符号列表
转义它:\- → -
使用反引号:`-`
HTML 实体语法:&#45;
代码块:~~~~~~~~
: 定义 当它是行上第一个非空白字符时 转义它:\:
使用反引号:`:`
HTML 实体语法:&#58;
代码块:~~~~~~~~
| 表格 当它在一个 TABLE 单元格中时
当它看起来像 TABLE 的第一行时
  (前面是空行,后面是
   包含“-”和“|”的行)
转义它:\| → |
使用反引号:`|`
HTML 实体语法:&#124;
代码块:~~~~~~~~
`
(反引号)
代码片段 当它与另一个 ` 连用时 不在 `code-span` 中时
  转义它:\`...\` → `…`
  使用 HTML 实体语法:&#96;
  代码块:~~~~~~~~
`code-span` 中时
  使用 `` f("`") `` f("`")
  (代码片段以双反引号 + 一个空格开头/结尾)
' '
(空格字符)
手动换行 当 Smartdown 行以两个或更多尾随空格结束时 不要使用尾随空格——删除它们。
如果您真的想手动换行,请使用 <br>

强制元字符显示为文字的另一种方法是将其放入 ~~~~ code-block ~~~~ 中。当然,代码块在屏幕上会有一个视觉上独特的块;这可能符合您的意愿,也可能不符合。

已知错误和解决方法

本节列举了已知的错误/怪癖,以及解决方法。

{if...}

错误: 如果您在 Markdown 中的任何位置使用字符序列 {if...}&123;if...&125;,Markdown 将会严重损坏(页面完全空白)。(这里的“任何位置”指的是普通文本、### 标题、`code-spans`~~~~code-blocks~~~~;任何地方。)

注意:... 部分表示任何字符,例如,{if foo}{if-foo}{iffy} 或任何其他以 if 开头的字符序列。

示例

语境 如果您
使用这个
或者如果您
使用这个
或者如果您
使用这个
那么这将
发生
在普通文本中 {if} {if blah} {iffy blah} 页面“崩溃”
(整个页面将为空白)
在标题中 ### {if} ### {if blah} ### {iffy blah} 页面“崩溃”
(整个页面将为空白)
`code-span` `{if}` `{if blah}` `{iffy blah}` 页面“崩溃”
(整个页面将为空白)
~~~~code-block~~~~ ~~~~
{if}
~~~~
~~~~
{if blah}
~~~~
~~~~
{iffy blah}
~~~~
页面“崩溃”
(整个页面将为空白)

解决方法

{if...} 出现在普通文本中(既不是 `code-span` 也不是 ~~~~code-block~~~~

不要使用
这个 Markdown
而是使用
这个 Markdown
读者看到的
结果
注释
{if...} (if...) (if…) 使用圆括号而不是花括号
{if...} { if...} { if…} 在左花括号后添加一个空格
{if...} {&#105;f...} {if…} i 编码为 &#105;

{if...} 出现在 `code-span` 中时

不要使用
这个 Markdown
而是使用
这个 Markdown
读者看到的
结果
注释
`{if...}` `(if...)` (if...) 使用圆括号而不是花括号
`{if...}` `{ if...}` { if...} 在左花括号后添加一个空格
`{if...}` <code>{&#105;f...}</code> {if...} i 编码为 &#105;
并使用明确的 <code>...</code>

{if...} 出现在 ~~~~code-block~~~~ 中时

  ~~~~
  Alternative 1:  (if...)    // use parens rather than braces
  Alternative 2:  { if...}   // add a space after the open brace
  ~~~~