带有大括号的 char 数组的非静态成员初始化在 gcc 中给出了一个错误,而不是在 clang 中

Non-static member initialization of char array with brace gives an error in gcc while not in clang

考虑以下代码:

#include <iostream>

class A
{
    char name[40] = { "Blank" }; // note the braces here
public:
    const char *getName() { return name; }
};

int main()
{
    A a;

    std::cout << a.getName() << std::endl;
}

gcc(最新版本5.2.0)报错:

prog.cpp:5:28: error: invalid conversion from 'const char*' to 'char' [-fpermissive]
  char name[40] = { "Blank" };
                            ^

clang 的情况并非如此,用 -std=c++11 -pedantic -Wall.

可以完美地编译它

在这里为非静态初始化器放大括号真的不正确吗?

AFAIR 有没有大括号并不重要。比如数组的定义,如:

char text[] = "some text";

相当于:

char text[] = { "some text" };

来自 C++ 标准工作草案 n4527 [dcl.init]。初始化可以这样写:

初始化器

initializer:
  brace-or-equal-initializer
  ( expression-list )

brace-or-equal-initializer:
  = initializer-clause
  braced-init-list

initializer-clause:
  assignment-expression
  braced-init-list
initializer-list:
  initializer-clause...opt
  initializer-list,initializer-clause...opt

braced-init-list:
  {initializer-list,opt}
  { }

一个Class成员声明

member-declarator:
  declarator virt-specifier-seq opt pure-specifier opt
  declarator brace-or-equal-initializer opt

根据我的阅读,gcc 似乎不符合标准。因为 class 使用大括号的成员初始化被标准接受。

fwiw,g++ 在基于大括号的初始化 and/or 构造函数调用方面存在一些问题,包括最近报告的一些问题。

但是(编辑),正如 Jonathan 正确指出的那样,其中大部分(全部?)都可以轻松解决。我已经成功地将旧的括号语法替换为受影响的代码位。

听到无法做到这一点的情况会很有教育意义,但谢天谢地,我个人还没有找到,所以 g++ 对我来说仍然非常有用(评论解释了我为什么使用在某些奇怪的地方使用旧语法!)

嗯,我认为标准不是很清楚,但我会说 CLang 是正确的:

8.5.1 说:

§2 : 当聚合由初始化列表初始化时,如 8.5.4 中所述,初始化列表的元素 被视为聚合成员的初始值设定项,以递增的下标或成员顺序。 那是 gcc 解释:名称是一个数组,有一个大括号初始化列表,所以数组的第一个元素(一个 char ) 使用 char 数组初始化 => error

但 8.5.2 明确指出:窄字符类型的数组...可以由窄字符串文字初始化...或由适当类型的字符串文字初始化用大括号括起来(强调我的)

我的解释是,该标准认为 char 数组足够特殊,可以明确允许括在大括号中的字符串文字有效,即使它违反了 8.5.1 §2

该代码有效,现在已被 GCC 主干接受。我认为它已被 PR 65815 brace elision doesn't work in NSDMI

修复