【问题标题】:Why was the space character not chosen for C++14 digit separators?为什么没有为 C++14 数字分隔符选择空格字符?
【发布时间】:2015-03-02 07:08:11
【问题描述】:

从 C++14 开始,感谢n3781(它本身并没有回答这个问题),我们可以编写如下代码:

const int x = 1'234; // one thousand two hundred and thirty four

目的是改进这样的代码:

const int y = 100000000;

并使其更具可读性。

下划线 (_) 字符在 C++11 中已被用户定义的文字采用,而逗号 (,) 存在本地化问题 — 许多欧洲国家莫名其妙地使用this 作为小数点分隔符 - 并且与逗号运算符冲突,尽管我确实想知道允许例如可能会破坏哪些实际代码1,234,567.

无论如何,更好的解决方案似乎是空格字符:

const int z = 1 000 000;

这些相邻的数字文字标记可以由预处理器连接起来,就像字符串文字一样:

const char x[5] = "a" "bc" "d";

相反,我们得到了撇号 ('),我所知道的任何书写系统都没有将它用作数字分隔符。

是否有理由选择撇号而不是简单的空格?


令人费解的是,所有这些语言在文本中都保持逗号“分解”原本原子句子的概念,句号用于“终止”句子- 至少对我来说,这非常类似于逗号“分解”数字的整数部分和句点“终止”它,为小数输入做好准备。

【问题讨论】:

  • 关于逗号,是不是逗号操作符的问题,而不是本地化问题?
  • @LightnessRacesinOrbit:我认为没有人打算改变int a[] = {123,000,000} 的含义。至于逗号与句号的区别,请注意这些都是最近标准化的——无论是文本还是数字。
  • 除了技术点之外,您说撇号 ('), [is] 不被我所知道的任何书写系统用作数字分隔符。有一个国家使用撇号作为数字分隔符:瑞士。我也曾在作者更喜欢它的情况下看到它,或者一个点/逗号会引起混淆,因为它们在国际上的使用方式不同。
  • 如果这让你感觉好些,我是欧洲人,感谢美国制造的许多产品(计算器等)使用逗号作为十进制值 - 幸运的是 - 非常缓慢地失去了味道.我想说 0.99 现在比 0.99 使用更广泛;使用逗号作为千位分隔符是闻所未闻的,就像使用点一样,我们只是不分隔它们(可能是因为现在 1,234 和 1.234 都表示小数)
  • @BenjaminLindley 我原以为逗号的问题是int foo(int);int foo(int,int); foo(1,000); 的含糊不清

标签: c++ language-lawyer c++14 digit


【解决方案1】:

之前有一篇论文n3499 告诉我们,尽管 Bjarne 本人建议使用空格作为分隔符:

虽然这种方法与一种常见的排版样式一致,但它存在一些兼容性问题。

  • 它与 pp-number 的语法不匹配,并且至少需要扩展该语法。
  • 更重要的是,当 [a-f] 范围内的十六进制数字跟在空格后面时,会出现一些语法歧义。预处理器不知道是否在空格之后开始执行符号替换。
  • 这可能会降低抓取“文字”的编辑工具的可靠性。

我猜下面的例子是注意到的主要问题:

const int x = 0x123 a;

虽然在我看来这个理由是相当薄弱的。我仍然想不出一个真实的例子来打破它。

“编辑工具”的原理更糟,因为1'234 基本上破坏了人类已知的所有语法荧光笔(例如,Markdown 在上述问题本身中使用的语法荧光笔!)并且使所述荧光笔的更新版本更难以实施。

不过,无论好坏,这都是导致采用撇号的理由。

【讨论】:

  • @aschepler:如果我是地球的总统,那么“文字”会在其生产中包含一个空间,从而使0x123 a45 成为一个单一的、尽管是多标记的文字。你能想到一个场景,在这种场景中a45 在这里被解释为整数文字的一部分是不受欢迎的吗?在它之前没有运算符或任何东西,所以它还能是什么?
  • #define abc + 1, const int x = 0x123 abc;
  • @T.C.宏在第 4 阶段扩展,字符串文字在第 6 阶段连接。我希望“数字文字连接”也发生在第 6 阶段,从而保持示例代码的行为并且不会破坏任何内容。
  • @LightnessRacesinOrbit 我不确定这是否那么容易。要允许宏替换,您必须将 abc 解析为 标识符,但随后您必须指定 pp-number标识符,这……很奇怪。此外,显然还有significant concerns with breaking Objective-C
  • @supercat:那是糟糕的代码,我宁愿我们不对其进行优化;p
【解决方案2】:

不使用空格的明显原因是换行也是 空白,并且 C++ 对待所有空白都是一样的。关闭 手,我不知道任何接受任意空白的语言 作为分隔符。

大概可以使用 Unicode 0xA0(不间断空格)——它是 排版时使用最广泛的解决方案。我看到两个问题 但是:首先,它不在基本字符集中,其次, 它在视觉上没有特色;你看不出它不是一个空间 只是在普通编辑器中查看文本。

除此之外,没有太多选择。你不能使用逗号,因为 这已经是一个合法的令牌(并且像 1,234 这样的东西目前是 合法的 C++,含义为 234)。在可能发生的情况下 在法律法规中,例如a[1,234]。虽然我无法想象任何真实的 代码实际使用这个,有一个基本规则就是没有合法程序, 不管多么荒谬,都应该默默地改变语义。

类似的考虑意味着_也不能使用;如果有一个 #define _234 * 2,然后a[1_234] 会默默地改变 代码。

我不能说我对' 的选择特别满意,但它 确实有在欧洲大陆使用的优势,至少在 某些类型的文本。 (我似乎记得在德语中看到过,因为 例如,尽管在典型的运行文本中,德语与大多数其他文本一样 语言,将使用一个点或一个不间断的空间。但也许是 瑞士德语。)' 的问题在于解析;序列'1' 是 已经合法,'123' 也是如此。所以像1'234 这样的东西可能是1, 后跟一个字符常量的开头;我不确定你有多远 必须向前看才能做出决定。没有合法的顺序 C++中整数常量后面可以跟一个字符 不变,所以打破法律法规没有问题,但这意味着 词法扫描突然变得非常依赖上下文。

(关于您的评论:选择一个没有逻辑 小数或千位分隔符。例如,小数分隔符是 当然不是句号。它们只是任意的约定。)

【讨论】:

  • “新行也是空白”。对不起,如果我听到傻话,但这是为什么呢? :)
  • @G.Samaras:C 将“空白”定义为“...空格、水平制表符、换行符、垂直制表符和换页”,这完全是传统的。跨度>
  • @LightnessRacesinOrbit 甚至void f(int); void f(int, int); f(12,345);
  • @CraigMcQueen 这是一个多字符文字。不是很有用,因为它是实现定义的性质。
  • @G.Samaras 因为 C++ 不是面向行的。新行的作用与语言中的任何其他空格完全相同。
【解决方案3】:

来自wiki,我们有一个很好的例子:

auto floating_point_literal = 0.000'015'3;

在这里,我们有 . 运算符,然后如果遇到另一个运算符,我的眼睛会等待可见的东西,比如逗号或其他东西,而不是空格。

因此,撇号在这里的效果比空格要好得多。

如果有空格

auto floating_point_literal = 0.000 015 3;

感觉不像撇号那样正确。


本着Albert Renshaw's answer 的精神,我认为撇号比轨道中的Lightness Races 提出的空间更清晰。

type a = 1'000'000'000'000'000'544'445'555;
type a = 1 000 000 000 000 000 544 445 555;

空格用于许多事情,例如 OP 提到的字符串连接,与撇号不同,在这种情况下,撇号使用于分隔数字的人清楚。

当代码行数变多的时候,我认为这会提高可读性,但我怀疑这就是他们选择它的原因。


关于空格,不妨看看这个 C question,上面写着:

该语言不允许 int i = 10 000;(整数文字是一个标记,中间的空格将其分成两个标记)但是将初始化程序表示为计算文字的表达式通常几乎不会产生任何费用:

int i = 10 * 1000; /* ten thousand */

【讨论】:

  • 您所表达的长数字通常不会以全零结尾,在这种情况下,您的 10*1000 示例不起作用。
  • @MarkRansom 这是从我链接的答案中粘贴的示例。你觉得我应该修改它吗?
  • 我想你知道那篇关于空白重载的论文的出版日期(特别是月和日,而不是年份),对吧?
  • 是的,不太现代,我要编辑@BenjaminLindley。
  • 它的现代性不是问题。仔细研究一下。如果日期在您所在的地区没有重要意义,请在 Google 上搜索。
【解决方案4】:

确实,我认为没有实际意义:

if (a == 1 1 1 1 1) ...

所以数字可能会在没有真正歧义的情况下合并 但是十六进制数呢?

0 x 1 a B 2 3

这样做无法消除拼写错误(通常我们应该看到错误)

【讨论】:

  • 嗯,很简单。现在它将是有效代码,而不是错误。拼写错误仍然会导致代码有效,如果您的“语言”包含多个单词,则绝对没有办法防止这种情况发生。
【解决方案5】:

我认为这是因为在编写代码时,如果您到达“行”(屏幕宽度)的末尾,则会发生自动换行(或“自动换行”)。这将导致您的 int 分成两半,其中一半位于第一行,另一半位于第二行...这样,在出现 word-wrap 时,它们都将保持在一起。

【讨论】:

  • 我不是 C++ 设计委员会的成员,但从我收集的信息来看,这些问题通常不会影响到决策制定。
  • 我不认为这是原因,但这是一个我没有考虑过的有趣的原因。从人们的更多答案中获得更多想法:)
  • @LightnessRacesinOrbit 此外,它可能还会阻止代码编译器忽略您的数字中断。空间会被剥夺,这些可以留下。但这只是一个愚蠢的可能性,任何人都会关心这个哈哈。
  • @AlbertRenshaw:我不关注?
【解决方案6】:
float floating_point_literal = 0.0000153;   /* C, C++*/

auto floating_point_literal = 0.0000153;    // C++11

auto floating_point_literal = 0.000'015'3;  // C++14

评论没有伤害:

/*  0. 0000 1530 */ 
float floating_point_literal = 0.00001530; 

二进制字符串可能很难解析:

long bytecode = 0b1111011010011001; /* gcc , clang */  

long bytecode = 0b1111'0110'1001'1001;  //C++14
// 0b 1111 0110 1001 1001  would be better, really.
// It is how humans think.

供考虑的宏:

#define B(W,X,Y,Z)    (0b##W##X##Y##Z)
#define HEX(W,X,Y,Z)  (0x##W##X##Y##Z)
#define OCT(O)        (0##O)



long z = B(1001, 1001, 1020, 1032 ); 

// result :  long z = (0b1001100110201032);

 long h = OCT( 35); 

// result :  long h  = (035); // 35_oct => 29_dec

 long h = HEX( FF, A6, 3B, D0 ); 

// result :  long h  = (0xFFA6BD0);

【讨论】:

  • 这没有回答问题。
  • 哦,是的,评论确实很痛苦。一个问题是评论可能是错误的,现在或将来。另一个是repetititititititition会妨碍可读性并且容易出错。
  • @Deduplicator 在这种情况下,很容易发现错误的评论(评论不会增加意义,它只是重新格式化下面的信息)。
  • 当然在这种情况下很容易发现。如果您稍微转移一下注意力,请尝试这样做。
【解决方案7】:

这与语言的解析方式有关。编译器作者很难重写他们的产品以接受空格分隔的文字。

另外,我认为用空格分隔数字并不常见。我见过,它总是非空白字符,即使在不同的国家。

【讨论】:

  • 无论如何他们不得不改变他们的解析器。
  • @BoundaryImposition 恐怕你不明白。空格在语言中已经有了意义。一个是根本的。将12'345'678(数字分隔符)更改为二进制形式与没有数字分隔符的情况大致相同。编译器作者需要付出同样多的努力。而重新定义标记化系统本身会很困难。加上空格分隔的数字看起来很难看。
  • 我可以向你保证我理解。 “代币化系统”不需要“重新定义”。例如,考虑字符串文字连接,它已经可以正常工作了。
  • 空白仅具有“基本”含义,因为它可以防止两个连续字符成为同一标记的一部分。正如 OP 所提到的,这可以很容易地插入到“连接相邻字符串文字”预处理器通道中。 (主)解析器甚至永远不会看到它。
  • 恐怕你对分词器过于神秘了。您可以像对字符串文字所做的那样做,在翻译阶段 6 中发生连接,即在阶段 6,["foobar"] ["frob"] 变为 ["foobarfrob]。或者可以扩展标记器以吸收空格:decimal_literal ::= [1-9][0-9]+[uU]?(l|L|ll|LL)? 变为 decimal_literal ::= [1-9][ 0-9]+[uU]?(l|L|ll|LL)?,在这种情况下,文字必须稍后进行规范化。与'的操作模式基本相同。不知道你真正想说什么:|
猜你喜欢
  • 1970-01-01
  • 2013-07-15
  • 1970-01-01
  • 2019-11-27
  • 2018-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多