MrMobster
MrMobster

Reputation: 1972

Constructor from a reference to array not selected for list initialisation

Given the following struct:

struct A {
    template<typename T, std::size_t N>
    A(T const(&array)[N]) {}

    template<typename T, std::size_t N>
    A& operator=(T const(&array)[N]) { return *this; }
 };

The code:

// a is of type A
a = {1, 2, 3, 4};

compiles just fine, since std::initialiser_list is implicitly converted to an array reference.

However,

A a {1, 2, 3, 4};
A a = {1, 2, 3, 4};

fails to compile with both Clang and GCC. It does compile when I add a constructor that accepts a std::initialiser_list<T>.

What am I missing?

Upvotes: 1

Views: 63

Answers (1)

Barry
Barry

Reputation: 302718

You just need extra braces or parens:

A a{{1, 2, 3, 4}}; // ok
A b({1, 2, 3, 4}); // ok

The reason for this is the outer braces/parens are for the A and in the inner braces are for the array object that you're list-initializing.

With assignment, you don't need the extra parens or braces because they're simply implied by the function call:

a = {1, 2, 3, 4};

is equivalent to:

a.operator=({1, 2, 3, 4});

More or less.


It does compile when I add a constructor that accepts a std::initialiser_list<T>.

To elaborate on how list-initialization works. When you write A a{1, 2, 3, 4}, we're looking first for some std::initializer_list<T> constructor (which we don't have yet, and so don't find one) and then look for a constructor that we can call with four arguments (which doesn't exist). Adding the extra ()s or {}s means we're looking for a constructor that we can call with one argument which we initialize with 1, 2 ,3, 4.

Once you add the std::initializer_list<T> constructor, now that's a viable candidate for that first phase of initialization.


Note that this:

compiles just fine, since std::initialiser_list is implicitly converted to an array reference.

is not right. There is no std::initializer_list anywhere in this question. {1, 2, 3, 4} is a funny thing in C++. It doesn't have a type or anything. It's just a braced-init-list. It's only based on context that we give it meaning. In this case, it's not a thing that's converted to a different thing... it's just a collection of initializers for the array.

Upvotes: 2

Related Questions