tgoop.com/cpplastic/377
Last Update:
Коли я тільки-но починав програмувати, то з величезним задоволенням писав на QBasic, а потім на Pascal. Згодом перейшов на
Але найбільше на початку дратувала робота з багатовимірними масивами. Якщо в тому ж паскалі можна дати змінній тип, наприклад, двовимірного масиву, щоб потім звертатися до його елементів як pixels[x,y]
, то в сішці таке не спрацює, і треба писати pixels[x][y]
.
Нічого страшного начебто — просто трохи інший запис. Але ця фішка перейшла і в
Уявімо, що написали ви свій клас Matrix
. Всередині у вас лежить якийсь масив; треба тепер визначити operator[]
, щоб можна було читати/писати конкретний елемент. Якби була багатовимірна індексація, то це суперлегко, причому дані всередині можна взагалі тримати в одновимірному масиві, а індекс обчислювати. Однак matrix[i][j]
— це дві окремі операції, які можна записати як (matrix[i])[j]
. Іншими словами, matrix[i]
має повернути щось, на чому потім можна викликати .operator[](j)
.
Що це може бути? Ну, по-перше, можна повертати тупо вказівник на початок рядка, проте, я не почуваюся комфортно з цього приводу, бо забагато свободи: можна за межі піти, можна зберегти у змінну кудись, а потім навіть не дізнатися, що він інвалідувався (бо не володієш ним) тощо. При обережному використанні працюватиме, але наша мета ж знизити когнітивне навантаження, а не навпаки.
По-друге, можна повертати якийсь проксі-обʼєкт власного типу на кшталт Matrix::Row
. Зробити, щоб створювати його могла тільки сама Matrix
, по максимуму обмежити допустимі операції, перевизначити operator[]
… Головняково якось, ще й сумнівно з погляду на швидкодію.
Натомість зазвичай перевантажують не індексацію, а операцію виклику функції operator()
. Тоді є змога вказати довільну кількість параметрів. Але використання вже не настільки файне на вигляд, бо дужки круглі: matrix(i, j)
. Окрім неможливості в такому випадку зробити одночасно й індексацію, і виклик обʼєкта як функції (що все одно навряд чи комусь знадобиться), мені в цьому не подобається, що воно складніше сприймається. Око вже звикло, що квадратні дужки — доступ до елемента, круглі — виклик функції, тому натренований токенайзер у мозку даватиме хибні результати й сповільнюватиме читання й розуміння коду.
В інших, кращих мовах багатовимірна індексація вже присутня. Не тільки в спеціалізованих на кшталт int[,]
), а по-друге, кастомний індексатор може приймати більше одного параметра: this[int row, int column]
. (Так, мені дійсно подобається C# місцями). У Python __getitem__
завжди приймає тільки один параметр, проте, коли ви пишете matrix[i,j]
, то оці значення через кому запаковуються в кортеж, тобто викликається Matrix.__getitem__(matrix, (i, j))
.
Щодо C++ же я давно змирився, що зручно тут не буває. І, уявіть собі, дарма!
Короч, починаючи з C++23 тепер є багатовимірна індексація, тобто це вже працює. Тепер operator[]
може приймати довільну кількість параметрів різних типів:
m[0, 1, "shiii~"] = 42;
І до купи цей оператор тепер ще й статичним може бути.
Не вау яка фіча, і все ж мені до душі.