2013-12-05 3 views
6

Согласно GCC 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) Мне не хватает фигурную скобку в инициализации массива в следующем коде:Действительно ли требуются фигурные скобки вокруг инициализации?

#include <iostream> 
#include <boost/array.hpp> 
#include <array> 

int main(){ 
    int     plain[] = {1,2,3,4,5}; 
    std::array <int, 5> std_arr = {1,2,3,4,5}; // warning, see below 
    boost::array<int, 5> boost_arr = {1,2,3,4,5}; // warning, see below 
    std::cout << plain[0] << std_arr[1] << boost_arr[2] << std::endl; 
} 
> g++ test.cc -Wall -Wextra -pedantic --std=c++0x                     
test.cc: in function »int main()«: 
test.cc:7:47: warning: curly braces missing around initialization for »std::array::value_type [5] {aka int [5]}« [-Wmissing-braces] 
test.cc:8:47: warning: curly braces missing around initialization for »int [5]« [-Wmissing-braces]

По-видимому (GCC missing braces around initializer) это ошибка в GCC, даже в немного другом контексте. Ответы отличаются от «файла сообщения об ошибке» на «просто отключить предупреждение».

Однако, в контексте std::array или boost::array, является ли это предупреждение излишним, или я пропускаю что-то важное?

(я, вероятно, добавить дополнительные скобки вместо отключения предупреждения, но мне интересно, о последствиях)

+1

Это предупреждение. Если это было «необходимо», это было бы ошибкой. – geoffspear

+0

не должно быть 'std :: array Alex

+0

@Alex Нет, но 'std :: array arr {1,2,3,4,5};' будет законным. –

ответ

5

Я думаю, что это уже ответил here.

std :: массив смешно. Он определяется в основном следующим образом:

template struct std :: array {T a [size]; };

Это структура, которая содержит массив. Он не имеет конструктора , который принимает список инициализаторов. Но std :: array является агрегатом по правилам C++ 11, и поэтому он может быть создан путем агрегации инициализации. Для агрегирования инициализации массива внутри структуры вам понадобится второй набор фигурных скобок:

std :: array strings = {{"a", "b"}};

Обратите внимание, что стандарт предполагает, что дополнительные брекеты могут быть в этом случае. Вероятно, это ошибка GCC.

Я считаю, это может быть связано с this defect, которое было связано в нескольких вопросах.

Вот answer regarding it:

Однако эти дополнительные скобки могут быть опущены только «в декларации форма Т х = {а};» (C++ 11 §8.5.1/11), то есть когда используется старый стиль =. Это правило, разрешающее выравнивание фигур, не применяется для прямой инициализации списка. В сноске здесь говорится: «Скобки не могут быть удалены в других целях использования списка-инициализации».

Существует сообщение о дефекте относительно этого ограничения: CWG дефект # 1270. Если принятая предлагаемая резолюция будет принята, то будет разрешено выравнивание фигур для других форм инициализации списка, ...

Я заметил, что ошибка не появляется в gcc 4.8.1, но она работает на очень старой версии (4.4.7), и я думаю, что это патч (потому что дефекта предложенное решение от февраля 2012, и эта связь от марта 2012):

http://gcc.gnu.org/ml/gcc-patches/2012-03/msg00215.html

+0

Да, хороший ответ +1 –

+0

Обратите внимание, что приведенный пример имеет форму 'T x = {a};'. Таким образом, применяется только последняя цитата. CWG 1270 охватывает другие случаи, например. тот в Alex'comment на вопрос. – MSalters

+0

@remyabel: «полезный комментарий», который вы цитировали, подразумевает, что существует принципиальная разница между инициализацией класса агрегата и встроенной инициализацией массива. Похоже, что совокупный класс обрабатывается «классической» агрегатной инициализацией, а инициализация массива - это новая инициализация списка инициализаторов. Разве это различие действительно существует в C++ 11?В C++ 03 и до того, как массивы были агрегатами, что означает, что все было обработано равномерно путем агрегатной инициализации. – AnT

2

Нет, нет действительно никакого способа, в котором разумный компилятор может испортить это, для класса это просто.

+0

Я ожидал бы разумного компилятора, чтобы жаловаться на несоответствующий код, и это происходит здесь. Я вижу вашу точку зрения, но это может показаться действительно неправильным. – pmr

3

Это раздражающее предупреждение о безопасности, которое было введено в одной из ранних версий GCC для обоих инициализаторов C и C++. Если я правильно помню, он предшествует C++ 11 и на самом деле не связан с C++ 11 (опять же, он влияет на C так же сильно, как на C++). В принципе, для ввода вложенного агрегата требуется дополнительный уровень вложенных {}. Язык этого не требует, поэтому это просто предупреждение.

Предупреждение, о котором идет речь, может быть полезным во многих случаях, но реализация была плохо продумана. Одно совершенно нелепое следствие этого предупреждения состоит в том, что он «убивает» идиоматику инициализации = { 0 } на языке С. (В C все можно инициализировать с помощью = { 0 }, но из-за этого раздражающего предупреждения один из них вынужден выборочно использовать такие вещи, как = {{0}}, = {{{0}}} и т. Д.).

В C++ std::array класс представляет собой совокупность, для которой инициализаторы = { ... } обрабатываются доброй старой встроенной инициализацией агрегата, а не специальным конструктором. (В C++ 11 правила инициализации агрегата были переписаны в терминах списков инициализаторов , но общее поведение стиля C было намеренно сохранено с помощью возможности brace elision.) По этой причине на инициализацию также влияет это предупреждение. std::array - это совокупность, содержащая фактический массив, который также является совокупностью. По этой причине, чтобы добраться до элементов массива в инициализаторе, GCC рекомендует вам открыть два уровней {}.

Итак, с std::array вы просто нашли другой пример того, когда это предупреждение наносит больше вреда, чем пользы.

Смежные вопросы