3

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?

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Very nice, thanks. I already tried this but there is a warning if I add default constructor - multiple default constructors specified(VS2013 preview)
With g++ or clang++ i don't get a warning when I add MyStruct() = default;. You may be able to use some enable_if trickery for that, but I can't come up with something right now that works. This could also allow you to only enable the constructor with the right number of arguments instead of triggering the assertion. See seanmiddleditch.com/journal/2012/03/…
1

std::array does not have a constructor! And it doesn't use initializer_list, instead it uses uniform initialization. (similar to POD structures, actually std::array is POD structure).

So what std::array really does is very similar to the following:

template<int size, typename T>
struct array {
   T data[size];
   // and some member function here;
   // Warning! No constructors !
};

When, later, you write

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

It is equivalent to

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

And this is just POD initialization where {1,2,3} is assigned to data.


If you want to enforce having the same size checking in compile time it's possible using std::array itself instead of std::initializer_list.

If you change your initializations from {1,2,3} to std::array<3, int>{1, 2, 3} and constructor argument from std::initializer_list<T> to std::array<SIZE, T> user will be enforced to pass array with size SIZE.

4 Comments

MyStruct has compile time constant size LIKE std::array, it's not std::array. I need contructors to initialize with default values if there are no values provided.
But std::array<3, int> arr = {1,2} does initialize with default value arr[2] although you didn't provide it yourself. arr[2] will be equal to 0
But... maybe default value is not 0. Think about a color where I want to use default value 255 or 1.f, depending on color representation.
Thanks for the answer. I won't accept it for now - I need to use clasic syntanx to build MyStruct. Using it like this is very confusing.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.