Reputation: 20790
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
?
Upvotes: 3
Views: 745
Reputation: 22670
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.
Upvotes: 2
Reputation: 14715
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
.
Upvotes: 1