Инициализация std:: array <char, x> член в конструкторе с использованием строкового литерала. Ошибка GCC?

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

#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

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

Ответ 1

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

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

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

Здесь у нас есть целевой объект типа S, который инициализируется с копией (8.5p15) из списка с привязкой к элементарной строке {"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, а элементы массива char инициализируются последовательными символами строки (8.5.2p1).

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

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"});

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