Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initializing an array with an initializer_list/converting initializer_list to a parameter pack

Tags:

c++

I need to initialize a compile-time sized class array with an initializer_list. I'm already aware that I could use a parameter pack constructor and initialize it on the spot, but I need to use an initializer_list in this case. I'd also like to avoid dynamically initializing the array if possible. Here's the pseudo-code:

template<typename Type, std::size_t Length>
class Test
{
    public:
        Test(const std::initializer_list<Type> args)
        :   m_tData(args) //<-- Doesn't work of course
        {}

    private:
        Type m_tData[Length];
};

Of course, for non-const types, I could do

Test(const std::initializer_list<Type> args)
{
    std::copy(args.start(), args.end(), m_tData);
}

but this doesn't work if I try to use a const class like Test<const int, 3>({1, 2, 3}). Am I forced to use template specialization to have the internal array not actually be const so I can initialize it from the constructor body?

I'm using C++20. I've seen How do I initialize a member array with an initializer_list? but was wondering if anything has changed since then.

like image 907
code-gs Avatar asked Jun 04 '19 15:06

code-gs


1 Answers

Possible solution:

template<typename Type, std::size_t Length>
class Test
{
public:
    Test(std::initializer_list<Type> args) :
        Test(args, std::make_index_sequence<Length>{})      
    {
        assert(args.size() == Length);
    }

private:
    template<std::size_t... ii>
    Test(std::initializer_list<Type> args, std::index_sequence<ii...>) :
        m_tData{(*(args.begin() + ii))...}
    {}

    Type m_tData[Length];
};

https://godbolt.org/z/d8Zg3q

Is there a way I could still support initializer_lists of lesser lengths than the templated length? Say something like Test<const int, 5>({1, 2, 3})?

If the remaining elements are supposed to be initialized with Type{}, just a slight modification is needed:

Test(std::initializer_list<Type> args) :
    Test(args, std::make_index_sequence<Length>{})      
{
    assert(args.size() <= Length);
}

template<std::size_t... ii>
Test(std::initializer_list<Type> args, std::index_sequence<ii...>) :
    m_tData{(ii < args.size() ? *(args.begin() + ii) : Type{})...}
{}
like image 164
Evg Avatar answered Sep 22 '22 12:09

Evg