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

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

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

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

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

Ответы [ 18 ]

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

Вы можете перегрузить operator[], чтобы вернуть объект, для которого вы можете использовать operator[] снова, чтобы получить результат.

class ArrayOfArrays {
public:
    ArrayOfArrays() {
        _arrayofarrays = new int*[10];
        for(int i = 0; i < 10; ++i)
            _arrayofarrays[i] = new int[10];
    }

    class Proxy {
    public:
        Proxy(int* _array) : _array(_array) { }

        int operator[](int index) {
            return _array[index];
        }
    private:
        int* _array;
    };

    Proxy operator[](int index) {
        return Proxy(_arrayofarrays[index]);
    }

private:
    int** _arrayofarrays;
};

Тогда вы можете использовать его как:

ArrayOfArrays aoa;
aoa[3][5];

Это простой пример, вы хотели бы добавить кучу проверок границ и прочее, но вы поняли идею.

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

Выражение x[y][z] требует, чтобы x[y] оценивал объект d, который поддерживает d[z].

Это означает, что x[y] должен быть объектом с operator[], который оценивается как "прокси-объект", который также поддерживает operator[].

Это единственный способ связать их.

Либо перегрузите operator(), чтобы получить несколько аргументов, например, вы можете вызвать myObject(x,y).

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

В частности, для двумерного массива вы можете избежать перегрузки с одним оператором [], которая возвращает указатель на первый элемент каждой строки.

Затем вы можете использовать встроенный оператор индексации для доступа к каждому элементу в строке.

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

Это возможно, если вы возвращаете какой-то прокси-класс в первом вызове [].Однако есть и другой вариант: вы можете перегрузить operator (), который может принимать любое количество аргументов (function(3,3)).

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

Один подход использует std::pair<int,int>:

class Array2D
{
    int** m_p2dArray;
public:
    int operator[](const std::pair<int,int>& Index)
    {
       return m_p2dArray[Index.first][Index.second];
    }
};

int main()
{
    Array2D theArray;
    pair<int, int> theIndex(2,3);
    int nValue;
    nValue = theArray[theIndex];
}

Конечно, вы можете typedef pair<int,int>

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

Было бы здорово, если бы вы дали мне знать, что такое function, function[x] и function[x][y].Но в любом случае позвольте мне рассматривать его как объект, объявленный где-то вроде

SomeClass function;

(поскольку вы сказали, что это перегрузка оператора, я думаю, вас не заинтересует массив типа SomeClass function[16][32];)

Итак, function является экземпляром типа SomeClass.Затем найдите объявление SomeClass для типа возвращаемого значения перегрузки operator[], как

ReturnType operator[](ParamType);

Тогда function[x] будет иметь тип ReturnType.Снова ищите ReturnType для перегрузки operator[].Если есть такой метод, вы можете использовать выражение function[x][y].

Примечание. В отличие от function(x, y), function[x][y] - это 2 отдельных вызова.Поэтому компилятору или среде выполнения сложно гарантировать атомарность, если вы не используете блокировку в контексте.Аналогичный пример: libc говорит, что printf является атомарным, в то время как последовательные вызовы перегруженного operator<< в выходном потоке - нет.Оператор типа

std::cout << "hello" << std::endl;

может иметь проблемы в многопоточном приложении, но что-то вроде

printf("%s%s", "hello", "\n");

вполне подходит.

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

Вы можете использовать прокси-объект, что-то вроде этого:

#include <iostream>

struct Object
{
    struct Proxy
    {
        Object *mObj;
        int mI;

        Proxy(Object *obj, int i)
        : mObj(obj), mI(i)
        {
        }

        int operator[](int j)
        {
            return mI * j;
        }
    };

    Proxy operator[](int i)
    {
        return Proxy(this, i);
    }
};

int main()
{
    Object o;
    std::cout << o[2][3] << std::endl;
}
2 голосов
/ 28 мая 2016
template<class F>
struct indexer_t{
  F f;
  template<class I>
  std::result_of_t<F const&(I)> operator[](I&&i)const{
    return f(std::forward<I>(i))1;
  }
};
template<class F>
indexer_t<std::decay_t<F>> as_indexer(F&& f){return {std::forward<F>(f)};}

Это позволяет вам взять лямбду и создать индексатор (с поддержкой []).

Предположим, у вас есть operator(), который поддерживает передачу обеих координат в onxe в качестве двух аргументов. Теперь написание [][] поддержка просто:

auto operator[](size_t i){
  return as_indexer(
    [i,this](size_t j)->decltype(auto)
    {return (*this)(i,j);}
  );
}

auto operator[](size_t i)const{
  return as_indexer(
    [i,this](size_t j)->decltype(auto)
    {return (*this)(i,j);}
  );
}

И готово. Пользовательский класс не требуется.

2 голосов
/ 11 октября 2014
struct test
{
    using array_reference = int(&)[32][32];

    array_reference operator [] (std::size_t index)
    {
        return m_data[index];
    }

private:

    int m_data[32][32][32];
};

Нашел свое простое решение для этого.

2 голосов
/ 17 сентября 2013
#include<iostream>

using namespace std;

class Array 
{
     private: int *p;
     public:
          int length;
          Array(int size = 0): length(size)
          {
                p=new int(length);
          }
          int& operator [](const int k)
          {
               return p[k];
          }
};
class Matrix
{
      private: Array *p;
      public: 
            int r,c;
            Matrix(int i=0, int j=0):r(i), c(j)
            {
                 p= new Array[r];
            }
            Array& operator [](const int& i)
            {
                 return p[i];
            }
};

/*Driver program*/
int main()
{
    Matrix M1(3,3); /*for checking purpose*/
    M1[2][2]=5;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...