【问题标题】:Two curiosities with the C++ grammarC++ 语法的两个好奇心
【发布时间】:2015-10-18 16:48:00
【问题描述】:

§5.2[expr.post]/1 我们有 expression-list

的定义

表达式列表
初始化列表

为什么我们需要这两个定义?

§8.5[dcl.init]/1 我们有:

支撑初始化列表
{ 初始化列表,opt }
{ }

为什么我们需要上面可选的,

注意这个 sn-p 编译:

struct A{
    int i;
    float f;
    A(int i, float f) : i(i), f(f) {}
};

int main()
{
    A a = { 1, 2., };
}

【问题讨论】:

  • 第二个问题已经在别处得到解答(由 Jon Skeet 本人 IIRC)
  • 其他地方是here
  • 花括号初始化列表中的逗号来自 C,当您 a) 生成带有某些内容的列表 b) 当您将列表分布在多行并且想要添加时,它们很有用一个项目或对列表进行排序。统一性有助于简化编辑任务。
  • @chris 感谢您的链接
  • 第一个可能是出于历史原因。在 C++03 中,expression-list 实际上是一个逗号分隔的 assignment-expression 列表。然后在 C++11 中,他们希望也允许使用大括号初始化器,并且与跨标准进行手术相比,更改 expression-list 的产生可能更简单且不易出错。

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


【解决方案1】:

可选的尾随逗号使编写无需修改现有行即可扩展的代码变得容易(非常适合源代码管理)。

例如,制作一个数组:

int x[] = {
    1,
    2,
    3,
};

如果要添加,只需在新行上添加4,,并且完全避免使用3, 修改行。这不是必需的,但允许这样做很好。

【讨论】:

  • 对于自动生成的内容也很好(添加对最后一个元素的检查显然很简单,但它不必要地使代码复杂化)。
  • @MatteoItalia,认识std::experimental::ostream_joiner :)
  • @MatteoItalia: “为最后一个元素添加检查显然很简单” That's not always true
  • 好吧,将每个元素生成为<separator> <data>,将<separator>初始化为一个空字符串,并将其设置为, 输出每个元素之后.在每个元素之后重置分隔符的开销不太重要。
  • 如果您想对行进行排序,这也非常有用。
【解决方案2】:

结尾的逗号是 C 的遗留物,我们可以在 C99 rationale 中看到这一点:

K&R 允许在初始值设定项的末尾使用尾随逗号 初始化列表。标准保留了这种语法,因为它 提供从初始化程序中添加或删除成员的灵活性 列表,并简化此类列表的机器生成。

这也是comp.lang.c++.moderated: Are comma-separated lists ending in a comma legal?中引用的原因:

是的,这是合法的。一个原因是让每一行在语法上都相似,以帮助自动工具处理大型初始化列表

我们可以在Annotated C++ Reference Manual(ARM) 中找到有关不同初始化风格的更详细背景,它解释了语法中一些奇怪的起源,它说以下关于[dcl.init] 重点是我的:

显然有太多用于初始化的符号,但每个符号似乎都很好地服务于特定的使用风格。 ={initializer_list,opt} 表示法是从 C 继承而来的,可以很好地用于数据结构和数组的初始化。 [...] =expression 表示法也来自 C,最适合初始化简单变量,尤其是算术或指针类型的变量 [...] {expression-list} 表示法用于初始化来自 Simula,并且在创建不适合算术模型的类型的对象时似乎是最好的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-02
    • 1970-01-01
    • 1970-01-01
    • 2012-04-12
    • 2017-12-06
    相关资源
    最近更新 更多