c++ - Constructor for nested initializer lists -


is possible have generic constructor takes type of initializer list, if has nested lists within?

say have following partial template specialization class takes in constructor nested initializer lists:

template class classa;

template <> class classa<4> {    typedef std::initializer_list<double> list_type;   typedef std::initializer_list<list_type> llist_type;   typedef std::initializer_list<llist_type> lllist_type;   typedef std::initializer_list<lllist_type> initializer_type;    size_t n_[4] = {0};   double* data_;  public:    classa(initializer_type l) {      assert(l.size() > 0);     assert(l.begin()->size() > 0);     assert(l.begin()->begin()->size() > 0);     assert(l.begin()->begin()->begin()->size() > 0);      size_t m = n_[0] = l.size();     size_t n = n_[1] = l.begin()->size();     size_t o = n_[2] = l.begin()->begin()->size();     n_[3] = l.begin()->begin()->begin()->size();      data_ = new double[m*n*o*n_[3]];      int i=0, j=0, k=0, p=0;     (const auto& u : l) {       assert(u.size() == n_[1]);       (const auto& v : u) {         assert(v.size() == n_[2]);         (const auto& x : v) {           assert(x.size() == n_[3]);           (const auto& y : x) {             data_[i + m*j + m*n*k + m*n*o*p] = y;             ++p;           }           p = 0;           ++k;         }         k = 0;         ++j;       }       j = 0;       ++i;     }   }    size_t size() const {     size_t n = 1;     (size_t i=0; i<4; ++i)       n *= n_[i];     return n;   }    friend std::ostream& operator<<(std::ostream& os, const classa& a) {     (int i=0; i<a.size(); ++i)       os<<" "<<a.data_[i];     return os<<endl;   }  };   int main() {    classa<4> tt = { {{{1.}, {7.}, {13.}, {19}}, {{2}, {8}, {14}, {20}}, {{3}, {9}, {15}, {21}}}, {{{4.}, {10}, {16}, {22}}, {{5}, {11}, {17}, {23}}, {{6}, {12}, {18}, {24}}} };   cout<<"tt -> "<<tt<<endl;    return 0; } 

this code prints:

tt ->  1 4 2 5 3 6 7 10 8 11 9 12 13 16 14 17 15 18 19 22 20 23 21 24 

now, i'm trying generalize constructor don't have specialize class template each dimension. problem when replace constructor like:

template <class l> classa(std::initializer_list<l> l) {   cout<<"generic list constructor"<<endl; } 

the clang compiler fails error:

error: no matching constructor initialization of 'classa<4> 

can point out why happening? template matching not working initializer lists, because new c++ feature? thank all...

edit

thanks of @johannesschaub-litb , @daniel frey, able craft generic constructor takes initializer_list of dimension. resulting code:

template <int d, typename t> class classa {    size_t n_[d] = {0};   t* data_;    template <int d, typename u>   struct initializer_list {      typedef std::initializer_list<typename initializer_list<d-1,u>::list_type > list_type;      initializer_list(list_type l, classa& a, size_t s, size_t idx) {        a.n_[d-d] = l.size();        size_t j = 0;       (const auto& r : l)         initializer_list<d-1, u> pl(r, a, s*l.size(), idx + s*j++);     }   };    template <typename u>   struct initializer_list<1,u> {      typedef std::initializer_list<t> list_type;      initializer_list(list_type l, classa& a, size_t s, size_t i) {        a.n_[d-1] = l.size();       if (!a.data_)         a.data_ = new t[s*l.size()];        size_t j = 0;       (const auto& r : l)         a.data_[i + s*j++] = r;     }   };    typedef typename initializer_list<d,t>::list_type initializer_type;  public:    // initializer list constructor   classa(initializer_type l) : data_(nullptr) {     initializer_list<d, t> r(l, *this, 1, 0);   }    size_t size() const {     size_t n = 1;     (size_t i=0; i<4; ++i)       n *= n_[i];     return n;   }    friend std::ostream& operator<<(std::ostream& os, const classa& a) {     (int i=0; i<a.size(); ++i)       os<<" "<<a.data_[i];     return os<<endl;   } };  int main() {    classa<4, double> tt = { {{{1.}, {7.}, {13.}, {19}}, {{2}, {8}, {14}, {20}}, {{3}, {9}, {15}, {21}}}, {{{4.}, {10}, {16}, {22}}, {{5}, {11}, {17}, {23}}, {{6}, {12}, {18}, {24}}} };   cout<<"tt -> "<<tt<<endl;    return 0; } 

of course code prints

tt ->  1 4 2 5 3 6 7 10 8 11 9 12 13 16 14 17 15 18 19 22 20 23 21 24 

i love template metaprogramming stuff! thank guys helping figuring out.

aa

i believe want automatically build right type

template<int s, typename e> class make_list_type { public:   typedef std::initializer_list<     typename make_list_type<s-1, e>::type   > type; };  template<typename e> class make_list_type<0, e> { public:   typedef e type; };  template<int s> class classa {   typedef typename make_list_type<s, double>::type initializer_type;  public:   classa(initializer_type l)  }; 

as why try did not work, see templates don't guess initializer list types


Comments