title: Safe way to implement matrix class with bracket operators
body: <p>I am writing a bidimensional matrix class just for the sake of it, wrapping a vector of vectors.</p>
  
  <p>Since matrices must have positive dimensions I make sure the matrix cannot be ill-constructed, and from then on I assume the matrix has at least one element:</p>
  
  <pre><code>Matrix2D::Matrix2D(size_t rows, size_t cols)
  {
      if (rows == 0 || cols == 0)
      {
          throw std::invalid_argument("Matrix cannot have zero as dimension");
      }
      ...
  </code></pre>
  
  <p>I want to offer the user a way of accessing and modifying particular elements by using the concatenated <code>[]</code> (i.e. <code>m[1][1]</code>). However, I don't want the user to be able to modify the dimension of the matrix or to modify the number of columns in one row. My current approach of offering the overloaded <code>operator[]</code> like below is not enough, since the user can use the non-const version (necessary for modifying particular elements) to modify the number of columns:</p>
  
  <pre><code>std::vector&lt;double&gt;&amp; operator[](size_t r);
  const std::vector&lt;double&gt;&amp; operator[](size_t r) const;
  </code></pre>
  
  <p>by doing <code>m[0] = std::vector&lt;double&gt;(0)</code>.</p>
  
  <p><strong>Is there a way of preventing this downfall while keeping the double bracket syntaxis?</strong></p>
  
  <p>I am aware I could use <code>operator()</code> like <code>m(1, 1)</code>, but I'm curious about trying to use the double bracket syntaxis.</p>