2D counterpart of std::array in C++17 I implemented a 2D counterpart of std::array named array2d in C++17. It is an aggregate like std::array, and provides similar interface. The goal is that if you know how to use std::array, then you will find yourself at home using array2d. Any comments are welcome :) For better viewing experience with highlighting, you can refer to this GitHub page.

#include &lt;cstddef&gt;
#include &lt;array&gt;
#include &lt;iterator&gt;

template &lt;typename T, std::size_t N0, std::size_t N1&gt;
struct array2d {
  using row_t = std::array&lt;T, N1&gt;;
  inline static constexpr std::array sizes{ N0, N1 };

  static constexpr std::size_t size() noexcept { return N0 * N1; }
  static constexpr bool empty() noexcept { return !size(); }

  T&amp; at(std::size_t i, std::size_t j) { return data_.at(i).at(j); }
  const T&amp; at(std::size_t i, std::size_t j) const { return data_.at(i).at(j); }

  row_t&amp; operator[](std::size_t i) noexcept { return data_[i]; }
  const row_t&amp; operator[](std::size_t i) const noexcept { return data_[i]; }

  T&amp; front() { return data_.front().front(); }
  const T&amp; front() const { return data_.front().front(); }

  T&amp; back() { return data_.back().back(); }
  const T&amp; back() const { return data_.back().back(); }

  T* data() noexcept { return data_.data()-&gt;data(); }
  const T* data() const noexcept { return data_.data()-&gt;data(); }

  T* begin() noexcept { return data(); }
  const T* begin() const noexcept { return data(); }

  T* end() noexcept { return data() + size(); }
  const T* end() const noexcept { return data() + size(); }

  auto rbegin() noexcept { return std::make_reverse_iterator(end()); }
  auto rbegin() const noexcept { return std::make_reverse_iterator(end()); }

  auto rend() noexcept { return std::make_reverse_iterator(begin()); }
  auto rend() const noexcept { return std::make_reverse_iterator(begin()); }

  void fill(const T&amp; v) {
    for (auto&amp; row : data_) {
      row.fill(v);
    }
  }

  friend void swap(array2d&amp; a, array2d&amp; b) { a.data_.swap(b.data_); }

  std::array&lt;row_t, N0&gt; data_;
};
Let me collect a couple of thoughts here.


Aggregate initialization currently works like this:

array2d&lt;int, 2, 2&gt; a{{1, 2, 3, 4}};


but wouldn't it be favorable to allow for

array2d&lt;int, 2, 2&gt; a{{1, 2}, {3, 4}};

std::array::at performs bound checking and throws upon an out of bounds index. When your intention is to stick with the std::array interface, you should do the same.
If you want the container to be standard-compliant, there are some type aliases missing and maybe more. In particular, there are no cbegin(), cend(), crbegin(), crend() member functions. Is this intended?
You implicitly use row-major order. Are you sure everyone expects this? Users familiar with Eigen and their fixed size matrices might at least want to customize row-/column-major ordering, e.g. Eigen::Matrix&lt;int, 2, 2, Eigen::ColMajor&gt; m;
A range based for loop will considerably differ from a manual loop over rows and columns. Example:

// Loop over elements, transposed access. Requires nested loop.
for (std::size_t i = 0; i &lt; 2; ++i)
   for (std::size_t j = 0; j &lt; 2; ++j)
      std::cout &lt;&lt; a[j][i] &lt;&lt; "\n";

// Loop over elements, tranposed access impossible. Only one loop.
for (const auto&amp; i : d)
    std::cout &lt;&lt; i &lt;&lt; "\n";


This is slightly unintuitive. Shouldn't the range based for loop require a nested loop as well?
The static data member sizes is not used anywhere.


Getting a two-dimensional array to work is not that much of an effort. Getting the semantics right is hard. Sticking to the std::array interface is a good goal when ease of use is intended for those familiar with the std::array template. But the additional dimension pulls in requirements that can't be tackled with the concepts of std::array. I would recommend having a look at established linear algebra libraries and their fixed size matrices. Also, the mdspan proposal for a multi-dimensional view on array types might be a good read.