0

I have designed a matrix class. Now I would like to initialize via list

Matrix3D m2{{1,2,3},{4,5,6},{7,8,9}};

instead of

Matrix3D m1(1,2,3,4,5,6,7,8,9);

I have added a static assert to force the size of the matrix which does not work.

How should I modify the constructor?

#include <iostream>
using namespace std;

class Matrix3D
{
    int a11;
    int a12;
    int a13;
    int a21;
    int a22;
    int a23;
    int a31;
    int a32;
    int a33;

public:
    Matrix3D(
        int a11,
        int a12,
        int a13,
        int a21,
        int a22,
        int a23,
        int a31,
        int a32,
        int a33):
        a11(a11),
        a12(a12),
        a13(a13),
        a21(a21),
        a22(a22),
        a23(a23),
        a31(a31),
        a32(a32),
        a33(a33)        
    {

    }

    Matrix3D(std::initializer_list<std::initializer_list<double>> listlist);

};

Matrix3D::Matrix3D(std::initializer_list<std::initializer_list<double>> listlist)
{
    constexpr int rows = (int)(listlist.begin()).size();
    constexpr int cols = (int)listlist.size();
    static_assert(rows == 3, "");
    static_assert(cols == 3, "");

    a11=(listlist.begin()+0)[0];
    a12=(listlist.begin()+0)[1];
    a13=(listlist.begin()+0)[2];
    a21=(listlist.begin()+1)[0];
    a22=(listlist.begin()+1)[1];
    a23=(listlist.begin()+1)[2];
    a31=(listlist.begin()+2)[0];
    a32=(listlist.begin()+2)[1];
    a33=(listlist.begin()+2)[2];
}

int main() {
    Matrix3D m1(1,2,3,4,5,6,7,8,9);
    Matrix3D m2{{1,2,3},{4,5,6},{7,8,9}};
    return 0;
}
ar2015
  • 5,558
  • 8
  • 53
  • 110

1 Answers1

1

I have added a static assert to force the size of the matrix which does not work.

Unfortunately for your situation std::initializer_list<Elem> is designed for a variable number of elements, which is why you cannot statically say anything about its size in the general case. The fact that its size member is constexpr is a red herring:

constexpr std::initializer_list<int> constant_expr = { 0, 2, 4, 6 };
// this is what a constexpr size member makes possible
static_assert( constant_expr.size() == 4 );

std::initializer_list<int> non_constant_expr = { 1, 3, 5 };
// this can't work
//static_assert( non_constant_expr.size() == 3 );

Function parameters are not constant expressions.

Instead, you would be better served by a type with a statically known number of elements. Array references can be suited to your needs:

class Matrix3D {
    using index_type = int;
    static constexpr index_type cols = 3;
    using row_arg_type = int[cols];

public:
    Matrix3D(row_arg_type const& row0, row_arg_type const& row1, row_arg_type const& row2);

    // rest of class omitted
};

// number of rows and row width are statically enforced
Matrix3D m = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };

Coliru demo

Luc Danton
  • 34,649
  • 6
  • 70
  • 114
  • It seems `=` in `m = {` is redundant. – ar2015 Mar 14 '18 at 02:28
  • I didnt know that `{` initializes the normal constructor too. – ar2015 Mar 14 '18 at 02:28
  • and +1 for `[[maybe_unused]]` – ar2015 Mar 14 '18 at 02:29
  • 1
    @ar2015 The equals sign in a variable definition with initializer is the difference between [explicit and non-explicit construction](https://stackoverflow.com/questions/121162/what-does-the-explicit-keyword-mean), it's up to you as the class designer to choose [what to allow or not](http://coliru.stacked-crooked.com/a/598fd3d54811cf9f) – Luc Danton Mar 14 '18 at 02:38