Нестатическая инициализация члена массива char с помощью скобки дает ошибку в gcc, а не в 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" };

Ответ 1

Ну, на мой взгляд, стандарт не очень ясен, но я бы сказал, что CLang прав:

8.5.1 говорит:

§2: Когда агрегат инициализируется списком инициализаторов, как указано в 8.5.4, элементы списка инициализаторов берутся как инициализаторы для членов совокупности, увеличивая индекс или порядок членов. Это gcc-интерпретация: name - это массив, есть список элементов-скобок, поэтому первый элемент массива (a char) инициализируется с помощью char array = > error

Но в 8.5.2 явно сказано: массив узкого символьного типа... может быть инициализирован узким строковым литералом... или строковым литералом с соответствующей строкой, заключенным в фигурные скобки (подчеркиваем мой)

Моя интерпретация заключается в том, что стандарт рассматривает массивы char как достаточно специальные, чтобы явно разрешить строковый литерал, заключенный в фигурные скобки, как действительный, даже если он побеждает 8.5.1 §2

Ответ 2

Код действителен и теперь принимается магистралью GCC. Я думаю, что это было исправлено с помощью PR 65815 elce не работает в NSDMI

Ответ 3

Из стандартного рабочего проекта С++ 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}
  { }

Объявление члена класса

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

Из того, что я прочитал, похоже, что gcc не соответствует стандарту. Поскольку инициализация члена класса с использованием фигурных скобок принимается стандартом.

Ответ 4

fwiw, g++ имеет несколько проблем с инициализацией на основе скобок и/или вызовом конструктора, в том числе с некоторыми из недавних сообщений.

Однако (редактирование), как справедливо указал Джонатан, большинство (всех?) из них можно легко обойти. У меня был успех, заменив синтаксис старой скобки на поврежденные биты кода.

Было бы полезно услышать о ситуации, когда этого не может быть сделано, но, к счастью, я лично ее не нашел, поэтому g++ остается в высшей степени пригодным для меня (с комментариями, объясняющими, почему я использую старый синтаксис в некоторые нечетные места!)