#include <iostream>
#include <sstream>
#include <algorithm>
using namespace std;

// Длина UTF-8 строки путём подсчёта начальных байт:
// эти байты имеют двоичный вид XXYYYYYY, где XX — 00, 01 или 11. Байты-продолжения начинаются с 10.
size_t u8_len(const /*string_view*/ string& s)
{
	return count_if(s.begin(), s.end(),
		[](char c){ return static_cast<uint8_t>(c) >> 6 != 0b10; });
}

class trexmerniy_massiv_strok
{
public:
	trexmerniy_massiv_strok(size_t shirina, size_t vysota, size_t glubina, const string& filler);
	~trexmerniy_massiv_strok();
	string& operator ()(size_t x, size_t y, size_t z) const;
	friend ostream& operator <<(ostream& out, const trexmerniy_massiv_strok& m);

private:
	string* stroki;
	size_t shirina, vysota, glubina;
};

trexmerniy_massiv_strok::trexmerniy_massiv_strok
(
	size_t shirina, size_t vysota, size_t glubina, const string& filler
)
	: shirina(shirina), vysota(vysota), glubina(glubina)
{
	size_t array_size = glubina * vysota * shirina;
	stroki = new string[array_size];
	fill(stroki, stroki + array_size, filler);
	cout << "Создан массив " << shirina << " × " << vysota << " × " << glubina << " и залит \"" << filler << "\"." << endl;
}

trexmerniy_massiv_strok::~trexmerniy_massiv_strok()
{
	delete[] stroki;
	cout << "Массив уничтожен, расходимся." << endl;
}

string& trexmerniy_massiv_strok::operator ()(size_t x, size_t y, size_t z) const
{
	return stroki[z * vysota * shirina + y * shirina + x];
}

ostream& operator <<(ostream& out, const trexmerniy_massiv_strok& m)
{
	for (size_t z = 0; z < m.glubina; z++)
	{
		if (z > 0) out << endl;
		out << "Z = " << z << endl;
		for (size_t y = 0; y < m.vysota; y++)
		{
			if (y > 0) out << endl;
			for (size_t x = 0; x < m.shirina; x++)
			{
				if (x > 0) out << " ";
				string& s = m(x, y, z);
				string pad(max<ptrdiff_t>(0, 7 - static_cast<ptrdiff_t>(u8_len(s))), ' ');
				out << pad << s;
			}
		}
	}
	return out;
}

int main() {
	trexmerniy_massiv_strok m(3, 4, 2, "-");
	m(0, 0, 0) = "Этот";
	m(1, 0, 0) = "чудный";
	m(0, 1, 0) = "ротик";
	m(2, 1, 0) = "слишком";
	m(0, 0, 1) = "много";
	m(2, 1, 1) = "болтает";
	cout << m << endl;
	return 0;
}