Search code examples
c++c++11stlinitializer-liststdarray

Initializing an std::array with an std::intializer_list passed as a parameter


I am implementing a Matrix class in C++ and I want to be able to initialize it with an intializer list like so:

Matrix<double, 2, 3> m({{1,2,1}, 
                        {0,1,1}});

In the class I have implemented the constructor like this:

template<typename Ty, unsigned int rows, unsigned int cols>
class Matrix
{
    std::array<std::array<Ty, cols>, rows> data;
public:
    Matrix(const std::initializer_list<std::initializer_list<Ty>>& list)
    {
        int i = 0;
        for (auto& list_row : list)
        {
            int j = 0;
            for (auto& list_value : list_row)
            {
                data[i][j++] = list_value;
            }
            i++;
        }
    }
}

The code work but I have a couple of questions. Is it possible to make it safe, so it only takes initializer lists of a certain size(the size of the matrix) and secondly can I make the code more concise - I had imagined something like this:

Matrix(const std::initializer_list<std::initializer_list<Ty>>& list)
    : data(list)
{ }

And it doesn't work but any better way to do it would be appreciated.


Solution

  • There's a pretty easy way to make it safe:

    template<typename Ty, unsigned int rows, unsigned int cols>
    class Matrix
    {
        std::array<std::array<Ty, cols>, rows> data;
    public:
        Matrix(std::array<std::array<Ty, cols>, rows> const& in)
            : data(in)
        { }
    };
    

    This lets you almost use the syntax you want - you just need one extra set of {}s.

    There's no way to statically enforce the size of a std::initializer_list - you'd have to assert or throw to prevent me from passing in a bunch of extra values and causing you to perform out-of-range writes.