2

I've made a Matrix class with a constructor of this type:

Matrix<T>(const vector<vector<T>> &m)

If I do this I can instance a Matrix object:

vector<vector<double>> a_v {
        { 17,    24,    1},
        { 23,    5,     7 },
        {  4,     6,    13 }

    };

    Matrix<double> a=a_v;

It works correctly, but I think that che constructor should be act as type converter and I think that also this code should work:

    Matrix<double> a= {
    { 17,    24,    1},
    { 23,    5,     7 },
    {  4,     6,    13 }

};

However with this second code I get this error:

could not convert ‘{{17, 24, 1}, {23, 5, 7}, {4, 6, 13}}’ from 'brace-enclosed initializer list' to ‘Matrix’

Why C++11 does not convert the brace-enclosed initializer to vector<vector<double>> automatically?

What should I do if I want to initialize matrices in this way?

Andrea993
  • 663
  • 1
  • 10
  • 23
  • 1
    Possibly related https://stackoverflow.com/questions/15810171/is-there-a-way-to-pass-nested-initializer-lists-in-c11-to-construct-a-2d-matri – Saurav Sahu Aug 29 '17 at 12:48

1 Answers1

7

You have two options:

  1. add a constructor taking std::initializer_list<std::initializer_list<T>>
  2. eclose the init expression with another set of {} i.e.

    Matrix<double> a{{
        { 17,    24,    1},
        { 23,    5,     7 },
        {  4,     6,    13 }
    }};
    

Ok, I'll try a little explanation of what is going on here:

If there is no constructor taking a std::initializer_list then the outermost {} are always opening and closing the constructor call if you will, and not part of what you actually pass to the constructor.

Matrix<double> a{ {1, 2}, {3, 4} };
                ^ ^~~~~~~~~~~~~~ ^
                |  2 parameters  |
                |                |
                |                |
            opening            closing

As you can see this is taken as a constructor with 2 parameters, in this case 2 initializer_lists.

This is why you need another set of {}:

Matrix<double> a{ {{1, 2}, {3, 4}} };
                ^ ^~~~~~~~~~~~~~~~ ^
                |  1 parameter     |
                |                  |
                |                  |
            opening            closing

In order for the outermost {} to be considered an initializer_list then the constructor needs to have an overload taking a initializer_list. That is what is happening in the std::vector case.

bolov
  • 72,283
  • 15
  • 145
  • 224
  • I honestly don't have the energy now to go through the standard to see all the rules that come in play here, so until someone else does explain what is going on here you can take this at face value. – bolov Aug 29 '17 at 12:44
  • Thanks, it works, but why it needs another set of `{}`? – Andrea993 Aug 29 '17 at 12:52
  • I didn't check the standard and so I could be more or less wrong – bolov Aug 29 '17 at 13:01