czy istnieje sposób na przekazanie zagnieżdżonych list inicjalizatorów w C ++ 11 w celu skonstruowania macierzy 2D?

Wyobraź sobie, że masz prostą klasę macierzy

template <typename T = double>
class Matrix {

  T* data;
  size_t row, col;

public:

  Matrix(size_t m, size_t n) : row(m), col(n), data(new T[m*n]) {}
  //...       

  friend std::ostream& operator<<(std::ostream& os, const Matrix& m) {
    for (int i=0; i<m.row; ++i) {
      for (int j=0; j<m.col; ++j)
        os<<" "<<m.data[i + j*m.row];
      os<<endl;
    }
    return os;
  }
};      

Czy istnieje sposób na zainicjalizowanie tej macierzy za pomocą listy inicjalizującej? Mam na myśli uzyskanie rozmiarów macierzy i elementów z listy inicjalizatora. Coś podobnego do następującego kodu:

Matrix m = { {1., 3., 4.}, {2., 6, 2.}};

drukuje

 1 3 4
 2 6 2

Czekamy na twoje odpowiedzi. Dziękuję wam wszystkim. aa

EDYTOWAĆ

Pracowałem więc nad twoimi sugestiami, aby stworzyć nieco ogólną tablicę, która inicjuje elementy za pomocą list inicjalizacyjnych. Ale to najbardziej rodzajowy, jaki mogłem uzyskać. Byłbym wdzięczny, gdyby któryś z was miał jakieś sugestie, aby uczynić go bardziej ogólną klasą. Również kilka pytań:

Czy to w porządku, że klasa pochodna inicjalizuje stan klasy bazowej? Z tego powodu nie nazywam konstruktora bazowego, ale czy powinienem go tak nazywać?Zdefiniowałem destruktor jako klasę Generic_base jako chronioną, czy jest to właściwy sposób, aby to zrobić?Czy jest jakiś przewidywalny sposób na wykonanie kodu, który należy do konstruktora inicjatora w bardziej ogólny sposób? Mam na myślijeden generalny konstruktor, który zajmuje się wszystkimi sprawami?

Zawarłem tylko niezbędny kod, aby zilustrować użycie list inicjalizacyjnych w konstrukcji. Gdy idzie się do wyższych wymiarów, robi się bałagan, ale zrobiłem to tylko po to, by sprawdzić kod.

#include <iostream>
#include <cassert>

using std::cout;
using std::endl;


template <int d, typename T>
class Generic_base {

protected:

  typedef T value_type;

  Generic_base() : n_(), data_(nullptr){}

  size_t n_[d] = {0};
  value_type* data_;
};



template <int d, typename T>
class Generic_traits;


template <typename T>
class Generic_traits<1,T> : public Generic_base<1,T> {

protected:

  typedef T value_type;
  typedef Generic_base<1,T> base_type;
  typedef std::initializer_list<T> initializer_type;

  using base_type::n_;
  using base_type::data_;


public:

  Generic_traits(initializer_type l) {

    assert(l.size() > 0);
    n_[0] = l.size();
    data_ = new T[n_[0]];

    int i = 0;
    for (const auto& v : l)
      data_[i++] = v;
  }
};


template <typename T>
class Generic_traits<2,T> : public Generic_base<2,T> {

protected:

  typedef T value_type;
  typedef Generic_base<2,T> base_type;

  typedef std::initializer_list<T> list_type;
  typedef std::initializer_list<list_type> initializer_type;

  using base_type::n_;
  using base_type::data_;

public:

  Generic_traits(initializer_type l) {

    assert(l.size() > 0);
    n_[0] = l.size();
    n_[1] = l.begin()->size();

    data_ = new T[n_[0]*n_[1]];

    int i = 0, j = 0;
    for (const auto& r : l) {

      assert(r.size() == n_[1]);
      for (const auto& v : r) {
        data_[i + j*n_[0]] = v;
        ++j;
      }
      j = 0;
      ++i;
    }
  }
};


template <typename T>
class Generic_traits<4,T> : public Generic_base<4,T> {

protected:

  typedef T value_type;
  typedef Generic_base<4,T> base_type;

  typedef std::initializer_list<T> 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;

  using base_type::n_;
  using base_type::data_;

public:

  Generic_traits(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 T[m*n*o*n_[3]];

    int i=0, j=0, k=0, p=0;
    for (const auto& u : l) {
      assert(u.size() == n_[1]);
      for (const auto& v : u) {
        assert(v.size() == n_[2]);
        for (const auto& x : v) {
          assert(x.size() == n_[3]);
          for (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;
    }
  }
};



template <int d, typename T>
class Generic : public Generic_traits<d,T> {

public:

  typedef Generic_traits<d,T> traits_type;
  typedef typename traits_type::base_type base_type;

  using base_type::n_;
  using base_type::data_;

  typedef typename traits_type::initializer_type initializer_type;

  // initializer list constructor
  Generic(initializer_type l) : traits_type(l) {}

  size_t size() const {
    size_t n = 1;
    for (size_t i=0; i<d; ++i)
      n *= n_[i];
    return n;
  }

  friend std::ostream& operator<<(std::ostream& os, const Generic& a) {
    for (int i=0; i<a.size(); ++i)
      os<<" "<<a.data_[i];
    return os<<endl;
  }      
};


int main()
{

  // constructors for initializer lists

  Generic<1, double> y = { 1., 2., 3., 4.};
  cout<<"y -> "<<y<<endl;

  Generic<2, double> C = { {1., 2., 3.}, {4., 5., 6.} };
  cout<<"C -> "<<C<<endl;

  Generic<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;
}

Które drukuje zgodnie z oczekiwaniami:

y ->  1 2 3 4

C ->  1 4 2 5 3 6

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

questionAnswers(1)

yourAnswerToTheQuestion