Can I initialize an array using the std::initializer_list instead of brace-enclosed initializer?

后端 未结 3 904
轻奢々
轻奢々 2020-12-16 17:24

Can I initialize an array using the std::initializer_list object instead of brace-enclosed initializer?

As known, we can do this: http://en.cppreference

相关标签:
3条回答
  • 2020-12-16 17:59

    As far I know, no: you can't initialize a std::array with a std::initializer_list.

    The problem is that std::array is intended as a lightweight replacement (a wrapper) for the classic C-style array. So light that is without constructors, so only implicit constructor can be used.

    The construction with aggregate initialization (via implicit constructor) is possible because it's possible for the C-style array.

    But std::initializer_list is a class, more complicated than an aggregate inizialization.

    You can initialize, by example, a std::vector with a std::initializer_list but only because there is an explicit constructor, for std::vector, that receive a std::initializer_list. But std::vector is a heavier class.

    The only solution that I see is a 2 step way: (1) construction and (2) copy of the std::initializer_list values. Something like

    std::array<int, 3> arr5;
    
    auto  ui = 0U;
    auto  cit = il.cbegin();
    
    while ( (ui < arr5.size()) && (cit != il.cend()) )
       arr5[ui++] = *cit++;
    

    p.s.: sorry for my bad English.

    0 讨论(0)
  • 2020-12-16 18:01

    Other answered correctly said this is not possible upfront. But with little helpers, you can get pretty close

    template<typename T, std::size_T N, std::size_t ...Ns>
    std::array<T, N> make_array_impl(
        std::initializer_list<T> t,
        std::index_sequence<Ns...>) 
    {
        return std::array<T, N>{ *(t.begin() + Ns) ... };
    }
    
    template<typename T, std::size_t N>
    std::array<T, N> make_array(std::initializer_list<T> t) {
        if(N > t.size())
           throw std::out_of_range("that's crazy!");
        return make_array_impl<T, N>(t, std::make_index_sequence<N>());
    }
    

    If you are open to more work arounds, you can put this into a class to catch statically-known length violations for the cases where you pass a braced init list. But be warned that most people who read this code will head-desk

    template<typename T, std::size_t N>
    struct ArrayInitializer {
        template<typename U> struct id { using type = U; };
        std::array<T, N> t;
    
        template<typename U = std::initializer_list<T>>
        ArrayInitializer(typename id<U>::type z) 
            :ArrayInitializer(z, std::make_index_sequence<N>())
        { 
            if(N > z.size())
                throw std::out_of_range("that's crazy!");
        }
    
        template<typename ...U>
        ArrayInitializer(U &&... u)
           :t{ std::forward<U>(u)... }
        { }
    
    private:
        template<std::size_t ...Ns>
        ArrayInitializer(std::initializer_list<T>& t,
                         std::index_sequence<Ns...>)
           :t{ *(t.begin() + Ns) ... }
        { }
    };
    
    template<typename T, std::size_t N>
    std::array<T, N> f(ArrayInitializer<T, N> ai) {
        return std::move(ai.t);
    }
    
    int main() {
       f<int, 5>({1, 2, 3, 4, 5});  // OK 
       f<int, 5>({1, 2, 3, 4, 5, 6});  // "too many initializers for array<int, 5>"
    
       std::initializer_list<int> il{1, 2, 3, 4, 5};
       f<int, 5>(il); // ok
    }
    

    Note that both the non-static case at the top of the answer and the "head-desk" case do only check whether you provide too few initializing elements, and errors out then, for the initializer_list case. If you provide too many for the initializer_list case, the trailing elements are just ignored.

    0 讨论(0)
  • 2020-12-16 18:06

    The problem with std::array is that it is required to be an aggregate type, hence it does not have constructors.

    Hence only aggregate initialization or trivial copy are possible. std::initializer_list is a class other than std::array, so a (missing) implicit conversion is required.

    See http://en.cppreference.com/w/cpp/language/aggregate_initialization and http://en.cppreference.com/w/cpp/container/array for reference.

    0 讨论(0)
提交回复
热议问题