2014-02-04 3 views
10

Следующий пример, инициализирующий член std::array <char, N> в конструкторе с использованием строкового литерала, не компилируется в GCC 4.8, а компилируется с использованием Clang 3.4.Инициализация std :: array <char,x> член в конструкторе с использованием строкового литерала. Ошибка GCC?

#include <iostream> 
#include <array> 

struct A { 
    std::array<char, 4> x; 
    A(std::array<char, 4> arr) : x(arr) {} 
}; 


int main() { 
    // works with Clang 3.4, error in GCC 4.8. 
    // It should be the equivalent of "A a ({'b','u','g','\0'});" 
    A a ({"bug"}); 
    for (std::size_t i = 0; i < a.x.size(); ++i) 
     std::cout << a.x[i] << '\n'; 

    return 0; 
} 

При первом впечатлении это выглядит как ошибка GCC. Я чувствую, что он должен компилироваться, поскольку мы можем инициализировать std::array<char, N> непосредственно строковым литералом. Например:

std::array<char, 4> test = {"bug"}; //works 

Мне было бы интересно узнать, что говорит об этом Стандарт.

+0

Скомпонован с clang 3.5 (ствол 200501) с помощью '-Wall -Wextra' и работает так, как ожидалось. [Сообщения об ошибках с gcc online] (http://ideone.com/A0Wza7). – Ali

+0

FWIW, 'A a (std :: array {" bug "});' принимается GCC, поэтому «неизвестное преобразование для аргумента 1 из« <список с инициализатором, заключенным в скобки »> в 'std :: array «Мне очень странно выглядит. – hvd

+0

Я не понимаю, почему {{"bug"}} работает, вы запрашиваете 4-мерный массив символов, а не для строки (это другой зверь). Возможно, clang является умным и фиксирует код пользователя. –

ответ

2

Да, ваш код действителен; это ошибка в gcc.

Вот проще программа, которая показывает ошибку (я заменил std::array<char, 4> с S и избавившись от A, как мы можем продемонстрировать ошибку только в возвращении функции (это делает анализ более простым, так как мы не должны беспокоиться о конструкторе перегрузке):

struct S { char c[4]; }; 
S f() { return {"xxx"}; } 

Здесь мы имеем целевой объект типа S, который копия инициализируется (8.5p15) из рамно-Init-листа{"xxx"}, поэтому объект списка -инициализированный (8.5p17b1). S - это совокупность (8.5.1p1), поэтому выполняется агрегатная инициализация (8.5.4p3b1). При объединенной инициализации член c является с копией-инициализацией из соответствующего инициатор-статья"xxx" (8.5.1p2). Теперь вернемся к 8.5p17 с целевым объектом типа char[4] и инициализируем строковый литерал "xxx", поэтому 8.5p17b3 относится к 8.5.2, а элементы массива инициализируются последовательными символами строки (8.5.2p1).

Обратите внимание, что gcc в порядке с инициализацией копирования S s = {"xxx"}; при разрыве на различные формы копирования и прямой инициализации; Аргумент прохождения (в том числе и к конструкторам), возвращение функции и base- и член-инициализации:

struct S { char c[4]; }; 
S f() { return {"xxx"}; } 
void g(S) { g({"xxx"}); } 
auto p = new S({"xxx"}); 
struct T { S s; T(): s({"xxx"}) {} }; 
struct U: S { U(): S({"xxx"}) {} }; 
S s({"xxx"}); 

Последнее особенно интересно, поскольку это указывает на то, что это может быть связано с bug 43453.

+0

Вы уверены, что стандарт обрабатывает 'array ' специально в том смысле, что он позволяет инициализировать с помощью сжатого строкового литерала? IIRC, он не указывает внутреннее представление, поэтому мне кажется, что небезопасно предположить, что вы можете инициализировать его с помощью '= {string-literal}'. –

+0

@ JohannesSchaub-litb.AFAIK 'array ' - это тонкая оболочка вокруг «char [N]», которая сама может быть инициализирована строковым литералом, поэтому, как представляется, логически для «array » также можно инициализировать с использованием строкового литерала. Однако, хотя мне кажется логичным, это, в конечном счете, до стандарта. Если людям говорят, что они предпочитают «std :: array» над встроенными массивами C, я считаю, что важно поддерживать инициализацию строковых литералов. – Ricky65

+0

@ JohannesSchaub-litb, вы правы, конечно; 23.3.2.1p2 требует, чтобы 'array' был агрегатом, который принимает инициализацию копирования из списка инициализаторов, заключенных в скобки; член 'T elemens [N]' предназначен только для изложения, поэтому можно представить макет класса для 'array ', который не содержит непосредственно элемент 'char [N]'. – ecatmur