Search code examples
c++c++11initializer-liststdarray

How to build std::array like data structure from std::initializer_list


I want to implement a data structure with compile time constant size(like std::array). I want to be able to initialize this data structure like this:

MyStruct<3, int> example = {1, 2, 3};

This work fine using constructor like: MyStruct(std::initializer_list<T> elements), but the compiler doesn't enforce the same size for my internal structure and elements, even if they are both known at compile time.

I can't use static_assert because elements.size() is not compile time constant.

Is there any way to enforce at compile time same size for elements as in MyStruct?


Solution

  • You could try a constructor using variadic templates:

    template<std::size_t N, typename E>
    struct MyStruct {
        int otherStuff;
        E values[N];
    
        template<typename ...TT>
        MyStruct(TT&&...t) : values{std::forward<TT>(t)...} {
            static_assert(N == sizeof...(t), "Size mismatch!");
            for (size_t i = 0; i < N; i++) std::cout << values[i] << ",";
            std::cout << std::endl;
        }
    };
    

    This does work as expected with:

    MyStruct<3, int> example = {1,2,3};
    MyStruct<3, int> exampleFail = {1,2}; //error: static assertion failed: Size mismatch!
    

    Please note that there is still a difference between std:array and MyStruct when it comes to list-initialization:

    MyStruct<3, int> exampleList{1,2,3}; // works
    std::array<int, 3> arr = {1,2,3};    // works, but warning with clang++
    std::array<int, 3> arrList{1,2,3};   // works with g++, does not compile with clang++
    

    The reason is, that the single brace only works for std::array because of brace elision, which does not always apply as documented in an official defect report.