blog.michalt.pl

Wielowymiarowy operator tablicowy w C++ 23

07.02.2022 22:21 Tech

Niedawno zamieściłem artykuł, będący krótkim omówieniem nowości, których możemy się w spodziewać w najnowszym standardzie języka C++. Dziś poruszę temat jednej z nich. Będzie to wielowymiarowy wariant operatora tablicowego. Do testów wykorzystałem snapshot kompilatora GCC 12 z dnia 6 lutego 2022 roku, który w pełni to rozwiązanie wspiera. Aby zbudować przytoczone w dalszej części artykułu przykłady, należy dodać flagę -std=c++23.


Operator tablicowy dotychczas

Zacznijmy od starego operatora tablicowego. Dotąd w C++ mogliśmy go również przeciążać i nadawać mu różne typy parametrów – nie tylko numeryczne. Ów operator mógł przyjmować jako argument zarówno liczby całkowite jak i napisy, obiekty różnych klas i wskaźniki. Co ciekawe, można było go również szablonować.

Oto przykład:


#include <iostream>
#include <string>

class Test {

public:
    template<typename A>
    A operator[](A a) {

        std::cout << "operator template<typename A> void operator[](A a). Wartość:" << a << std::endl;
        return a;
    }

    void operator[](int a) {
        std::cout << "operator void operator[](int a). Wartość:" << a << std::endl;
    }

    Test operator[](Test a) {
        std::cout << "void operator[](Test a). Wartość:" << a.toString() << std::endl;
        return a;
    }

    std::string toString() const {
        return "Obiekt Test";
    }

};

int main() {
    Test n;
    Test m;

   n[6];
   n["test"];
   n[n];
   n[n][m];
}



Wynik działania kodu:

operator void operator[](int a). Wartość:6
operator template<typename A> void operator[](A a). Wartość:test
void operator[](Test a). Wartość:Obiekt Test
void operator[](Test a). Wartość:Obiekt Test
void operator[](Test a). Wartość:Obiekt Test

Co istotne, nie można stworzyć przeciążenia podwójnego dla dwóch operatorów, np. void operator[][](int a, b); Wywołanie przedostatniej linii to przykład wywołania operatora na obiekcie oraz zwracanym przez jego operator obiekcie.


Nowy operator tablicowy od standardu 23

W nowym standardzie, nasz operator będzie mógł przyjmować kilka argumentów. Jeśli na przykład będzie on przyjmował 2 parametry, jego wywołanie będzie wyglądać następująco:
zmienna[5,4];
Co istotne, tu również możemy podawać parametry różnego typu i również szablonować. Jedno przeciążenie może przyjmować kilka rodzajów parametrów, co ilustruje poniższy przykład:


#include <iostream>
#include <string>

class Test {

public:
    template<typename D>
    void operator[](int a, int b, std::string c, D d) {

        std::cout << a <<  "," << b  <<  ","  << c <<  "," << d << std::endl;
    }

    void operator[](int a, int b) {

        std::cout << a << "," << b << std::endl;
    }
};

int main() {
    Test n;

   n[6,7];
    n[7,4,"test", &n];

}


Wynik działania kodu:

6,7
7,4,test,0x7ffd1accba3f

Podsumowując

Ta nowość daje troszkę nowe możliwości w pisaniu algorytmów, jednak wydaje się ona nieco kontrowersyjna i zbędna, ponieważ podobny efekt moglibyśmy uzyskać implementując i wywołując metodę lub przeciążając operator wywołania funkcji (funktor). Może jednak jest tu jakiś głębszy sens? Ja go niestety nie widzę.
Niedługo następne wpisy o C++ 23. Do przeczytania!