get the size of `std::initializer_list` at compile time

3.7k views Asked by At

I am trying to implement the reshape function of fortran with C++(11/14) and I designed a function. This function accepts two std::initializer_list. The first initializer_list gives initial values which I use to initialize a D-dimensional array. The second initializer_list gives size of each dimension of the array. I wrote a draft like this

template<int D, typename T>
auto forreshape(const std::initializer_list<T> & values, const std::initializer_list<int> & shape)
{
    // some irrelevant codes to calculate lbound
    return for1array_gen<T, D>(lbound, shape, values); // returns D dimension array fornarray<T, D>
}
int main(){
    auto reshaped_array = forreshape<2>({1, 2, 3, 4, 5, 6}, {2, 3});
}

This implementation requires given non type template parameter int D, but I want something without D, like forreshape({1, 2, 3, 4, 5, 6}, {2, 3});. At first I want to use std::initializer_list<T>::size, however from static-assert-on-initializer-listsize I know it doesn't work. Looking around I found how-to-cause-a-compile-time-error-based-on-the-size-of-an-initializer-list but it didn't help to my case. I thought the compiler can get enough infomation and deduce value of int D automaticlly, but I don't know how. Maybe its a bad idea to use std::initializer_list? I got totally lost here

1

There are 1 answers

1
cpplearner On BEST ANSWER

Maybe its a bad idea to use std::initializer_list?

I think so. Consider

std::initializer_list<int> t;
std::initializer_list<int> a = {1,2,3};
std::initializer_list<int> b = {2,3};
if (rand() > 42)
    t = a;
else
    t = b;
auto reshaped_array = forreshape({1,2,3,4,5,6}, t);

In the above example, it's just impossible to know t.size() at compile time.

But you can ask the compiler to deduce the length of an initializer list by using a reference to C-style array, thanks to CWG 1591.

The definition of forreshape would look like:

template<int D, typename T>
auto forreshape(const std::initializer_list<T> & values, const int (&shape)[D])
{
    // use D...
}