Нестатическая инициализация члена массива 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++
остается в высшей степени пригодным для меня (с комментариями, объясняющими, почему я использую старый синтаксис в некоторые нечетные места!)