#include <vector>
#include <algorithm>
#include <type_traits>

template<typename T> class Row;
template<typename T> class ConstRow;

template<typename T>
class Matrix2D
{
   // Matrix aus bool nicht erlauben
   static_assert( !std::is_same<bool,T>::value, "T must not be bool because of std::vector<bool> anomaly" );

public:
   using value_type      = T;
   using reference       = T&;
   using const_reference = T const&;
   using pointer         = T*;
   using const_pointer   = T const*;
   using size_type       = std::size_t;
   using difference_type = std::ptrdiff_t;
   using row_type        = Row<T>;
   using const_row_type  = ConstRow<T>;

private:
   std::vector<T> Elements_;
   size_type      Rows_ = 0;
   size_type      Cols_ = 0;

public:
   Matrix2D() = default;
   Matrix2D( size_type rows, size_type cols ) :
      Matrix2D( rows, cols, value_type() )
   {
   }

   Matrix2D(size_type rows, size_type cols, const_reference v ) :
      Elements_( rows * cols, v ),
      Rows_( rows ),
      Cols_( cols )
   {
   }

   row_type operator[]( size_type index )
   {
      pointer beg = Elements_.data() + index * Cols_; 
      return row_type( beg, beg + Cols_ );
   }

   const_row_type operator[]( size_type index ) const
   {
       const_pointer beg = Elements_.data() + index * Cols_; 
       return const_row_type( beg, beg + Cols_ );
    }
};

template<typename T>
class Row
{
   T* Begin_= nullptr;
   T* End_  = nullptr;

public:
   Row( T* beg, T* end ) :
      Begin_( beg ),
      End_( end )
   {
   }

   bool empty() const
   {
      return Begin_ == End_;
   }

   std::size_t size() const
   {
      return std::distance( begin(), end() );
   }

   T& operator[]( std::size_t index )
   {
      return Begin_[index];
   }

   T const& operator[]( std::size_t index ) const
   {
      return Begin_[index];
   }

   T* begin()
   {
      return Begin_;
   }

   T* end()
   {
      return End_;
   }

   T const* begin() const
   {
      return Begin_;
   }

   T const* end() const
   {
      return End_;
   }
};

template<typename T>
class ConstRow
{
   T const* Begin_ = nullptr;
   T const* End_   = nullptr;

public:
   ConstRow( T const* beg, T const* end ) :
      Begin_( beg ),
      End_( end )
   {
   }

   ConstRow( Row<T> const& r ) :
      Begin_( r.begin() ),
      End_( r.end() )
   {
   }

   T const& operator[]( std::size_t index ) const
   {
      return Begin_[index];
   }
};

int main()
{
   Matrix2D<int> m( 2, 2,-1 );
   m[0][0] = 1;
}