Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to construct std::array object with initializer list? [duplicate]

Possible Duplicate:
How do I initialize a member array with an initializer_list?

You can construct an std::array just fine with an initializer list:

std::array<int, 3> a = {1, 2, 3};  // works fine

However, when I try to construct it from an std::initializer_list as a data member or base object in a class, it doesn't work:

#include <array>
#include <initializer_list>

template <typename T, std::size_t size, typename EnumT>
struct enum_addressable_array : public std::array<T, size>
{
    typedef std::array<T, size> base_t;
    typedef typename base_t::reference reference;
    typedef typename base_t::const_reference const_reference;
    typedef typename base_t::size_type size_type;

    enum_addressable_array(std::initializer_list<T> il) : base_t{il} {}

    reference operator[](EnumT n)
    {
        return base_t::operator[](static_cast<size_type>(n));
    }

    const_reference operator[](EnumT n) const
    {
        return base_t::operator[](static_cast<size_type>(n));
    }
};

enum class E {a, b, c};
enum_addressable_array<char, 3, E> ea = {'a', 'b', 'c'};

Errors with gcc 4.6:

test.cpp: In constructor 'enum_addressable_array<T, size, EnumT>::enum_addressable_array(std::initializer_list<T>) [with T = char, unsigned int size = 3u, EnumT = E]':
test.cpp:26:55:   instantiated from here
test.cpp:12:68: error: no matching function for call to 'std::array<char, 3u>::array(<brace-enclosed initializer list>)'
test.cpp:12:68: note: candidates are:
include/c++/4.6.1/array:60:12: note: std::array<char, 3u>::array()
include/c++/4.6.1/array:60:12: note:   candidate expects 0 arguments, 1 provided
include/c++/4.6.1/array:60:12: note: constexpr std::array<char, 3u>::array(const std::array<char, 3u>&)
include/c++/4.6.1/array:60:12: note:   no known conversion for argument 1 from 'std::initializer_list<char>' to 'const std::array<char, 3u>&'
include/c++/4.6.1/array:60:12: note: constexpr std::array<char, 3u>::array(std::array<char, 3u>&&)
include/c++/4.6.1/array:60:12: note:   no known conversion for argument 1 from 'std::initializer_list<char>' to 'std::array<char, 3u>&&'

How can I get it to work so that my wrapper class can be initialized with an initializer-list, as such:

enum_addressable_array<char, 3, E> ea = {'a', 'b', 'c'};
like image 955
HighCommander4 Avatar asked Aug 01 '11 02:08

HighCommander4


3 Answers

An std::array<> has no constructor that takes an std::initializer_list<> (initializer list constructor) and there is no special language support for what it may mean to pass a std::initializer_list<> to a class' constructors such that that may work. So that fails.

For it to work, your derived class needs to catch all elements and then forward them, a constructor template:

template<typename ...E>
enum_addressable_array(E&&...e) : base_t{{std::forward<E>(e)...}} {}

Note that you need {{...}} in this case because brace elision (omitting braces like in your case) does not work at that place. It's only allowed in declarations of the form T t = { ... }. Because an std::array<> consists of a struct embedding a raw array, that will need two level of braces. Unfortunately, I believe that the exact aggregate structure of std::array<> is unspecified, so you will need to hope that it works on most implementations.

like image 90
Johannes Schaub - litb Avatar answered Oct 02 '22 17:10

Johannes Schaub - litb


Since a std::array is a structure that contains an aggregate (it is not an aggregate itself, and does not have a constructor that takes a std::initializer_list), you can initialize the underlying aggregate inside the structure with an initializer list using a double-braces syntax like so:

std::array<int, 4> my_array = {{1, 2, 3, 4}};

Note that this is not using std::initializer_list ... this is simply using a C++ initializer list to initialize the publicly accessible array member of std::array.

like image 35
Jason Avatar answered Sep 28 '22 17:09

Jason


An std::array does not have a constructor that takes an std::initializer_list. It's a good thing, because initializer lists can be bigger than the fixed-size of the array.

You can initialize it by testing that the initializer list is not larger than the size of the array and then copying the elements of initializer list to the elems member of std::array with std::copy.

like image 30
R. Martinho Fernandes Avatar answered Sep 29 '22 17:09

R. Martinho Fernandes