Перегрузка оператора [] [] - PullRequest
       2

Перегрузка оператора [] []

83 голосов
/ 07 августа 2011

Возможно ли перегрузить оператор [] дважды? Чтобы разрешить, что-то вроде этого: function[3][3] (как в двумерном массиве).

Если это возможно, я хотел бы увидеть пример кода.

Ответы [ 18 ]

1 голос
/ 22 апреля 2018

Если вместо того, чтобы сказать [x] [y], вы хотели бы сказать [{x, y}], вы можете сделать так:

struct Coordinate {  int x, y; }

class Matrix {
    int** data;
    operator[](Coordinate c) {
        return data[c.y][c.x];
    }
}
1 голос
/ 20 июня 2012

Возможно перегрузить несколько [] с помощью специализированного обработчика шаблонов.Просто чтобы показать, как это работает:

#include <iostream>
#include <algorithm>
#include <numeric>
#include <tuple>
#include <array>

using namespace std;

// the number '3' is the number of [] to overload (fixed at compile time)
struct TestClass : public SubscriptHandler<TestClass,int,int,3> {

    // the arguments will be packed in reverse order into a std::array of size 3
    // and the last [] will forward them to callSubscript()
    int callSubscript(array<int,3>& v) {
        return accumulate(v.begin(),v.end(),0);
    }

};

int main() {


    TestClass a;
    cout<<a[3][2][9];  // prints 14 (3+2+9)

    return 0;
}

А теперь определение SubscriptHandler<ClassType,ArgType,RetType,N>, чтобы заставить работать предыдущий код.Это только показывает, как это можно сделать.Это решение является оптимальным и не содержит ошибок (например, не безопасным для потоков).

#include <iostream>
#include <algorithm>
#include <numeric>
#include <tuple>
#include <array>

using namespace std;

template <typename ClassType,typename ArgType,typename RetType, int N> class SubscriptHandler;

template<typename ClassType,typename ArgType,typename RetType, int N,int Recursion> class SubscriptHandler_ {

    ClassType*obj;
    array<ArgType,N+1> *arr;

    typedef SubscriptHandler_<ClassType,ArgType,RetType,N,Recursion-1> Subtype;

    friend class SubscriptHandler_<ClassType,ArgType,RetType,N,Recursion+1>;
    friend class SubscriptHandler<ClassType,ArgType,RetType,N+1>;

public:

    Subtype operator[](const ArgType& arg){
        Subtype s;
        s.obj = obj;
        s.arr = arr;
        arr->at(Recursion)=arg;
        return s;
    }
};

template<typename ClassType,typename ArgType,typename RetType,int N> class SubscriptHandler_<ClassType,ArgType,RetType,N,0> {

    ClassType*obj;
    array<ArgType,N+1> *arr;

    friend class SubscriptHandler_<ClassType,ArgType,RetType,N,1>;
    friend class SubscriptHandler<ClassType,ArgType,RetType,N+1>;

public:

    RetType operator[](const ArgType& arg){
        arr->at(0) = arg;
        return obj->callSubscript(*arr);
    }

};


template<typename ClassType,typename ArgType,typename RetType, int N> class SubscriptHandler{

    array<ArgType,N> arr;
    ClassType*ptr;
    typedef SubscriptHandler_<ClassType,ArgType,RetType,N-1,N-2> Subtype;

protected:

    SubscriptHandler() {
        ptr=(ClassType*)this;
    }

public:

    Subtype operator[](const ArgType& arg){
        Subtype s;
        s.arr=&arr;
        s.obj=ptr;
        s.arr->at(N-1)=arg;
        return s;
    }
};

template<typename ClassType,typename ArgType,typename RetType> struct SubscriptHandler<ClassType,ArgType,RetType,1>{
    RetType operator[](const ArgType&arg) {
        array<ArgType,1> arr;
        arr.at(0)=arg;
        return ((ClassType*)this)->callSubscript(arr);
    }
};
0 голосов
/ 11 декабря 2016

Используя C ++ 11 и Стандартную библиотеку, вы можете создать очень красивый двумерный массив в одной строке кода:

std::array<std::array<int, columnCount>, rowCount> myMatrix {0};

std::array<std::array<std::string, columnCount>, rowCount> myStringMatrix;

std::array<std::array<Widget, columnCount>, rowCount> myWidgetMatrix;

Решив, что внутренняя матрица представляет строки, вы получаете доступ к матрице с синтаксисом myMatrix[y][x]:

myMatrix[0][0] = 1;
myMatrix[0][3] = 2;
myMatrix[3][4] = 3;

std::cout << myMatrix[3][4]; // outputs 3

myStringMatrix[2][4] = "foo";
myWidgetMatrix[1][5].doTheStuff();

И вы можете использовать дальний диапазон - for для вывода:

for (const auto &row : myMatrix) {
  for (const auto &elem : row) {
    std::cout << elem << " ";
  }
  std::cout << std::endl;
}

(Решив, что внутренний array представляет столбцы, можно было бы использовать синтаксис foo[x][y], но для отображения вывода вам нужно было бы использовать неуклюжие циклы for(;;).)

0 голосов
/ 03 октября 2016

vector > или T ** требуется только при наличии строк переменной длины и слишком неэффективно с точки зрения использования памяти / распределения если вам нужен прямоугольный массив, подумайте о математике! см. в () метод:

template<typename T > class array2d {

protected:
    std::vector< T > _dataStore;
    size_t _sx;

public:
    array2d(size_t sx, size_t sy = 1): _sx(sx), _dataStore(sx*sy) {}
    T& at( size_t x, size_t y ) { return _dataStore[ x+y*sx]; }
    const T& at( size_t x, size_t y ) const { return _dataStore[ x+y*sx]; }
    const T& get( size_t x, size_t y ) const { return at(x,y); }
    void set( size_t x, size_t y, const T& newValue ) { at(x,y) = newValue; }
};
0 голосов
/ 09 октября 2015

Пример кода:

template<class T>
class Array2D
{
public:
    Array2D(int a, int b)  
    {
        num1 = (T**)new int [a*sizeof(int*)];
        for(int i = 0; i < a; i++)
            num1[i] = new int [b*sizeof(int)];

        for (int i = 0; i < a; i++) {
            for (int j = 0; j < b; j++) {
                num1[i][j] = i*j;
            }
        }
    }
    class Array1D
    {
    public:
        Array1D(int* a):temp(a) {}
        T& operator[](int a)
        {
            return temp[a];
        }
        T* temp;
    };

    T** num1;
    Array1D operator[] (int a)
    {
        return Array1D(num1[a]);
    }
};


int _tmain(int argc, _TCHAR* argv[])
{
    Array2D<int> arr(20, 30);

    std::cout << arr[2][3];
    getchar();
    return 0;
}
0 голосов
/ 31 августа 2018

Мои 5 центов.

Я интуитивно знал, что мне нужно сделать много шаблонного кода.

Вот почему вместо оператора [] я сделал перегруженный оператор (int, int),Затем в конечном результате вместо m [1] [2] я сделал m (1,2)

Я знаю, что это РАЗНОЕ, но все еще очень интуитивно понятно и похоже на математический сценарий.

0 голосов
/ 04 февраля 2019

Самое короткое и простое решение:

class Matrix
{
public:
  float m_matrix[4][4];

// for statements like matrix[0][0] = 1;
  float* operator [] (int index) 
  {
    return m_matrix[index];
  }

// for statements like matrix[0][0] = otherMatrix[0][0];
  const float* operator [] (int index) const 
  {
    return m_matrix[index];
  }

};
0 голосов
/ 20 августа 2014

Используя std::vector<std::vector<type*>>, вы можете построить внутренний вектор, используя пользовательский оператор ввода, который выполняет итерацию ваших данных и возвращает указатель на каждую информацию.

Например:

size_t w, h;
int* myData = retrieveData(&w, &h);

std::vector<std::vector<int*> > data;
data.reserve(w);

template<typename T>
struct myIterator : public std::iterator<std::input_iterator_tag, T*>
{
    myIterator(T* data) :
      _data(data)
    {}
    T* _data;

    bool operator==(const myIterator& rhs){return rhs.data == data;}
    bool operator!=(const myIterator& rhs){return rhs.data != data;}
    T* operator*(){return data;}
    T* operator->(){return data;}

    myIterator& operator++(){data = &data[1]; return *this; }
};

for (size_t i = 0; i < w; ++i)
{
    data.push_back(std::vector<int*>(myIterator<int>(&myData[i * h]),
        myIterator<int>(&myData[(i + 1) * h])));
}

Живой пример

Преимущество этого решения заключается в предоставлении вам реального контейнера STL, так что вы можете использовать специальные для циклов, алгоритмов STL и т. Д.

for (size_t i = 0; i < w; ++i)
  for (size_t j = 0; j < h; ++j)
    std::cout << *data[i][j] << std::endl;

Однако он создает векторы указателей, поэтому, если вы используете небольшие структуры данных, подобные этой, вы можете напрямую скопировать содержимое в массив.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...