Вівторкова порада з кодування 77 — Оператор підпису для багатовимірних масивів

Вівторкові поради з кодування — це короткі пости про різні дрібниці, здебільшого з C++, але також і з інших мов програмування, які я використовую. Ви також можете слідкувати за хештегом #TuesdayCodingTips на Mastodon та LinkedIn.

Функція, яка підвищує зручність у C++23, нарешті була інтегрована у Visual Studio (v17.12), після того як вона була доступна в Clang (trunk) досить довго. Ця функція — підтримка багатовимірного оператора підпису. Іншими словами, тепер ви можете перевантажити operator[] для роботи з будь-якою кількістю аргументів.

#include   
#include   
#include   

struct MdArray  
{  
 auto&& operator[](this auto&& self, size_t x, size_t y)  
 {  
 if (x >= W || y >= H)  
 throw std::out_of_range(  
 std::format(  
 "[{}, {}] is out of bounds of [{}, {}]", x, y, W, H));  
 return self.data[y * W + x];  
 }  

 void print()  
 {  
 for (unsigned y = 0; y < H; y++)  
 {  
 for (unsigned x = 0; x < W; x++)  
 std::print("{:02} ", (*this)[x, y]);  
 std::println();  
 }  
 }  

 constexpr static size_t W = 6;  
 constexpr static size_t H = 3;  
 std::array data = { 0 };  
};  

int main()  
{  
 MdArray mdArray;  
 mdArray[5, 2] = 42;  
 mdArray[1, 1] = 88;  
 mdArray[3, 0] = 69;  
 mdArray.print();  

 /* prints:  
 00 00 00 69 00 00   
 00 88 00 00 00 00   
 00 00 00 00 00 42   
 */  
}

Більше того, ця функція йде в парі з std::mdspan — це невласне багатовимірне подання для 1D колекції. Цей клас досить корисний, адже зберігання 2D/3D плиткових даних у вигляді 1D масиву є дуже поширеною технікою мікрооптимізації в розробці ігор.

#include   
#include   
#include   

int main()  
{  
 auto&& vec = std::vector { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };  

 // View into the data array as 3D array 2x3x2  
 auto&& span = std::mdspan(vec.data(), 2, 3, 2);  

 for (std::size_t x = 0; x < span.extent(0); ++x)  
 for (std::size_t y = 0; y < span.extent(1); ++y)  
 for (std::size_t z = 0; z < span.extent(2); ++z)  
 std::println("[{}, {}, {}]: {}", x, y, z, span[x, y, z]);  
}  

/*  
[0, 0, 0]: 1  
[0, 0, 1]: 2  
[0, 1, 0]: 3  
[0, 1, 1]: 4  
[0, 2, 0]: 5  
[0, 2, 1]: 6  
[1, 0, 0]: 7  
[1, 0, 1]: 8  
[1, 1, 0]: 9  
[1, 1, 1]: 10  
[1, 2, 0]: 11  
[1, 2, 1]: 12  
*/

Цікаво, що хоча Clang підтримував цей оператор задовго до MSVC, версія trunk, як зараз встановлено в Compiler Explorer, не підтримує std::mdspan.

Перекладено з: Tuesday Coding Tip 77 — Multidimensional subscript operator

Leave a Reply

Your email address will not be published. Required fields are marked *