С++ [] оператор массива с несколькими аргументами?

Могу ли я определить в C++ оператор массива, который принимает несколько аргументов? Я пробовал это так:

const T& operator[](const int i, const int j, const int k) const{ 
    return m_cells[k*m_resSqr+j*m_res+i];
}

T& operator[](const int i, const int j, const int k){ 
    return m_cells[k*m_resSqr+j*m_res+i];       
}

Но я получаю эту ошибку:

error C2804 binary operator '[' has too many parameters

person genesys    schedule 20.12.2009    source источник


Ответы (6)


Нет, вы не можете перегрузить operator[], чтобы он принимал несколько аргументов. Вместо этого вы можете перегрузить operator(). См. Как создать оператор индекса для класса Matrix? из FAQ по С++.

person jamesdlin    schedule 20.12.2009

Невозможно перегрузить оператор [], чтобы он принимал несколько аргументов, но в качестве альтернативы можно использовать шаблон прокси.

В двух словах: a[x][y] первое выражение (a[x]) вернет другой тип, названный прокси-типом, который будет иметь другой operator[]. Это вызовет что-то вроде _storedReferenceToOriginalObject->At(x,y) исходного класса.

Вы не сможете сделать a[x,y], но я предполагаю, что вы все равно хотели перегрузить обычный синтаксис двумерных массивов в стиле C++.

person Pavel Radzivilovsky    schedule 20.12.2009
comment
@ Нил Баттерворт: я думаю, что вы не можете этого сделать, но вот альтернатива, содержащаяся в ответе. - person jason; 20.12.2009
comment
Я думаю, он хотел синтаксис C 2D-массива a[x][y], который передал бы параметры оператору [](x,y), нет? Это действительно имело бы смысл. - person Pavel Radzivilovsky; 20.12.2009
comment
Comp.lang.c++ FAQ также рассматривает это: parashift .com/c++-faq-lite/operator-overloading.html#faq-13.11 - person jamesdlin; 20.12.2009
comment
Ссылка на часто задаваемые вопросы от @jamesdlin теперь isocpp.org/wiki/faq. /operator-overloading#matrix-array-of-array Почему интерфейс моего класса Matrix не должен выглядеть как массив массивов? - person TBBle; 08.05.2017
comment
почему нельзя сделать a[x, y]? Оператор запятой можно легко перегрузить, как это сделал Boost - person phuclv; 21.02.2019

Есть хороший небольшой трюк, который вы можете проделать с унифицированным синтаксисом инициализации, доступным в C++11. Вместо того, чтобы брать индекс напрямую, вы берете POD.

struct indices
{
  std::size_t i, j, k;
};

T& operator[](indices idx)
{
  return m_cells[idx.k * m_resSqr + idx.j * m_res + idx.i];
}

А затем используйте новый синтаксис:

my_array<int> arr;
// ...
arr[{1, 2, 3}] = 42;
person Jiří Pospíšil    schedule 10.12.2014
comment
Вам даже не нужно писать собственную структуру; вы можете просто использовать std::array или std::tuple - person Justin; 30.01.2018
comment
Даже std::initializer_list работает, если вам нужно неизвестное количество аргументов. Конечно, это не вписывается в этот точный пример. - person Razakhel; 08.02.2019

Для полноты: существует способ использовать оператор скобок с несколькими аргументами, если они не являются базовыми типами данных, а именно перегрузив оператор запятой, а не оператор скобок, см. следующий пост о перегрузка запятой:

https://stackoverflow.com/a/18136340/5836981

Отказ от ответственности: по моему мнению, перегрузка оператора запятой чревата ошибками и делает код более неясным, и его стоит рассматривать только в более экзотических случаях. Я добавил этот ответ, потому что я наткнулся на экземпляр этого в каком-то коде, и мне потребовалось некоторое время, чтобы понять, что ключом был не оператор [] (который нельзя перегружать несколькими аргументами), а оператор.

person tePer    schedule 02.02.2017
comment
ничего себе, я не знал, что вы можете иметь несколько аргументов в скобках, перегружая operator,, который является гениальным/злым-гением/вероятно-ужасной-идеей-большую часть времени. - person Trevor Boyd Smith; 02.08.2018

N-мерные массивы произвольного типа и размера в C++:

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

Я написал класс шаблона С++ для создания n-мерного массива произвольного типа и размера. Он должен быть создан с типом массива и количеством измерений. Размер может изменяться динамически. Ниже я привел голую (урезанную) рабочую версию того, как создать многомерный массив, к элементам которого можно получить доступ через последовательное применение operator[] (например, array[x][y] [з]). Эта версия может обрабатывать только массивы размерности n>1. Основная функция показывает, как создать 4-мерный массив целых чисел в качестве примера.

EDIT: имейте в виду, что приведенный ниже пример является минимальным для удобочитаемости, поскольку он не освобождает массив и не выполняет проверку границ при доступе. Добавление этого тривиально и оставлено на усмотрение программиста.

#include <stdio.h>
#include <stdlib.h>

template <typename T, int N>
struct array {
    array<T,N>() : data(NULL), offset((int*) malloc(sizeof(int)*N)){}
    array<T,N>(T *data, int *offset) : data(data), offset(offset){}
    array<T,N-1> operator[](int i){return array<T,N-1>(&data[i*offset[N]], offset);}
    bool resize(int *size){
        offset[N-1] = 1;
        int total_size = size[N-1];
        for(int i = N-2; i >= 0; i--){
            total_size *= size[i];
            offset[i] = offset[i+1]*size[i+1];
        }
        return (data = (T*) realloc (data, total_size*sizeof(T)));
    }
    T *data;
    int *offset;
};

template <typename T>
struct array<T,1>{
    array<T,1>(T *data, int *offset) : data(data){}
    T& operator[](int i){return data[i];}
    T *data;
};

int main () {
    array<int, 4> a;

    // create array with dimensions [1][3][3][7]
    int size[4] = { 1, 3, 3, 7 };
    a.resize(size);               

    a[0][1][2][3] = 123;

    return 0;
}

Наслаждаться.

person gospes    schedule 13.08.2014
comment
Это довольно хорошо, но я думаю, что это сбивает с толку то, что он называется array и выглядит точно так же, как std::array в объявлении, но имеет параметры шаблона (и семантику), которые очень сильно различаются (например, динамический размер!). Подумайте о том, чтобы дать ему другое имя. Также большой ew в заголовках C, malloc, realloc и free ... подождите минутку .... у вас нет free! Вы сливаете все данные. Хороший. - person Lightness Races in Orbit; 23.11.2014
comment
@LightnessRacesinOrbit: Думаю, я все еще должен вам деструктор с бесплатным :), но тогда я также чувствовал бы ответственность за обнаружение последовательных ошибок, вызванных любым доступом за пределы (например, доступом до изменения размера). Что касается заголовков C.. они занимают свое место в качестве получателей моего продолжающегося увлечения, то есть я остаюсь верным своим корням :) - person gospes; 24.11.2014
comment
Тогда -1 за то, что дал ужасно глючный код и опасный совет новичку в языке. - person Lightness Races in Orbit; 24.11.2014
comment
Спасибо господам за то, что сделали этот маленький перл общедоступным. +1 за дидактический пример и за умное использование рекурсивного шаблона. - person ; 22.08.2018

Изменить: как указано в комментарии, в операторе C++20 запятая будет объявлена ​​устаревшей, как и ответ ниже.

Вы не можете перегрузить operator[], но вы можете сымитировать, перегрузив вместо этого operator,.

Следуя вашему коду, он становится:

T& operator,(const int i, const int j, const int k){ 
    return m_cells[k*m_resSqr+j*m_res+i];       
}

теперь вы сможете звонить

something[1, 2, 3]

Вы можете расширить его, используя шаблоны, шаблоны с вариативными аргументами, std::pair или std::tuple в зависимости от вашего варианта использования и версии C++.

person Moia    schedule 16.01.2020
comment
Для информации: оператор запятой в операторе нижнего индекса устарел в C++20: eel.is/c++draft/depr.comma.subscript - person dgellow; 08.03.2020