Is gcc wrong to allow the initialization of a const array member with another array reference?


While (re)implementing a simple constexpr map, I wrote this

template <class key_type, class value_type, int N>
class flat_map
    struct pair
        key_type key;
        value_type value;
    const pair elements[N];

    consteval flat_map(const pair (&arr)[N]) noexcept
        : elements(arr) // works on gcc?!

    [[nodiscard]] consteval value_type operator[](const key_type key) const
        for (const pair &elem : elements)
            if (elem.key == key)
                return elem.value;
        throw "Key not found";

constexpr flat_map<int, char, 3> m = {{
    { 4, 'a' }, { -1, 'b' }, { 42, 'c' }
static_assert(m[4] == 'a');
static_assert(m[-1] == 'b');
static_assert(m[42] == 'c');

int main()
    return m[4]; // 97=='a'

I naively thought to set the private array elements as const and initialize it in the constructor; I was using gcc trunk as compiler, and all was seemingly working well.
When I decided to try it with msvc and clang, I had compilation errors: both were complaining about the array initialization requiring a brace-enclosed initializer list.

In hindsight the other compilers aren’t particularly wrong, are they?
Am I inadvertently using some gcc non standard extensions here?

Ehm, by the way, what would you do to avoid copying the array elements by hand?


  • You can't copy the elements by hand, once a const array is created you can't change it.

    – Mark Ransom

    10 hours ago

  • I think gcc got it wrong. No way you can initialize an array like this.

    – Sam Varshavchik

    10 hours ago

  • @MarkRansom Well you're right, const must be removed for that.

    – MatG

    10 hours ago

2 Answers



The expression-list or braced-init-list in a mem-initializer is used to initialize the designated subobject (or, in the case of a delegating constructor, the complete class object) according to the initialization rules of [dcl.init] for direct-initialization.


Otherwise, if the destination type is an array, the object is initialized as follows. Let x1, тАж, xk be the elements of the expression-list. If the destination type is an array of unknown bound, it is defined as having k elements. Let n denote the array size after this potential adjustment. If k is greater than n, the program is ill-formed. Otherwise, the ith array element is copy-initialized with xi for each 1 тЙд i тЙд k, and value-initialized for each k < i тЙд n. For each 1 тЙд i < j тЙд n, every value computation and side effect associated with the initialization of the ith element of the array is sequenced before those associated with the initialization of the jth element.

Point 16.5 takes precedence over all points that follow, in particular those that cover copy-initialization from a value of the same type (16.6 and 16.9). As such, an array data member can only be initialized by initializing each of the arrayтАЩs elements individually. GCCтАЩs behaviour is therefore non-conforming.


Am I inadvertently using some gcc non standard extensions here?

Yes… I suppose gcc is using a non standard extension

Ehm, by the way, what would you do to avoid copying the array elements by hand?

Why avoid it? Using a delegating constructor is simple.

You can substitute your constructor with the followings

template <std::size_t ... Is>
consteval flat_map(const pair (&arr)[N],
                   std::index_sequence<Is...> const &) noexcept
  : elements{ arr[Is]... }

consteval flat_map(const pair (&arr)[N]) noexcept
  : flat_map(arr, std::make_index_sequence<N>{})


  • 1

    I'll definitely try your suggestion, thank you!

    – MatG

    10 hours ago

Your Answer

Post as a guest

Required, but never shown

By clicking тАЬPost Your AnswerтАЭ, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged

or ask your own question.

Leave a Reply

Your email address will not be published. Required fields are marked *