#include <iostream>
#include <functional>
#include <algorithm>
#include <utility>
#include <memory>
#include <cstddef>
#include <cassert>
template<typename T>
struct matrix {
template<typename V>
struct index_proxy {
V & operator [](std::size_t const j) const {
assert(index < ref.height());
assert(j < ref.width());
return ref.data()[ref.width() * index + j];
}
operator V &() const {
assert(index < ref.size());
return ref.data()[index];
}
template<typename S>
void operator =(S && value) {
assert(index < ref.size());
ref.data()[index] = std::forward<S>(value);
}
private:
friend class matrix;
index_proxy(matrix & ref, std::size_t const index) : ref(ref), index(index) {}
index_proxy(index_proxy const&) = delete;
index_proxy(index_proxy &&) = delete;
matrix & ref;
std::size_t const index;
};
matrix(std::size_t const height_, std::size_t const width_)
: data_(new T[height_ * width_])
, height_(height_)
, width_(width_)
{}
matrix(matrix const& other) : matrix(other.height(), other.width()) {
std::copy_n(other.data(), size(), data());
}
matrix(matrix && other)
: data_(std::move(other.data_))
, height_(other.height_)
, width_(other.width_)
{}
matrix & operator =(matrix const& other) {
height_ = other.height();
width_ = other.width();
if (size() != other.size()) {
data().reset(new T[height() * width()]);
}
std::copy_n(other.data(), size(), data());
return *this;
}
matrix & operator =(matrix && other) {
data_ = std::move(other.data_);
height_ = other.height_;
width_ = other.width_;
return *this;
}
index_proxy<T> operator [](std::size_t const index) {
return {*this, index};
}
index_proxy<T const> operator [](std::size_t const index) const {
return {*this, index};
}
std::size_t height() const {
return height_;
}
std::size_t width() const {
return width_;
}
std::size_t size() const {
return height() * width();
}
T * data() {
return data_.get();
}
T const* data() const {
return data_.get();
}
private:
std::unique_ptr<T[]> data_;
std::size_t height_;
std::size_t width_;
};
int main() {
matrix<int> m(3, 4);
for (std::size_t i = 0; i != m.size(); ++i) {
m[i] = static_cast<int>(i);
}
for (std::size_t i = 0; i != m.size(); ++i) {
std::cout << m[i] << ' ';
}
std::cout << std::endl;
for (std::size_t i = 0; i != m.height(); ++i) {
for (std::size_t j = 0; j != m.width(); ++j) {
std::cout << m[i][j] << ' ';
}
std::cout << std::endl;
}
}