2010-11-22 2 views
3

Я хочу иметь что-то вроде этого ниже:Как реализовать оператор [] для этой структуры?

template <class T> 
struct Container{ 
public: 
    //[] operator 
private: 
    T containment; 
}; 

сдерживание должен быть массивом с любым избирательным числом измерений, как показано ниже:

Container<int[20][4]> obj; 
Container<int[5][2][6]> obj1; 
//etc... 

И я хочу, чтобы реализовать [] чтобы были возможны следующие назначения:

obj[2][3]=6; 
obj1[1][1][3]=3; 
//etc... 

Но после нескольких попыток я оказался застрял, как это возможно?

+0

Кстати, зачем вам нужен такой контейнер? Как насчет рассмотрения boost :: array или boost :: multi_array? – upriser 2010-11-22 17:27:07

ответ

1

Кто думал, что ссылка будет входить в игру здесь? меня!
Благодаря Niki Yoshiuchi, Ответ в точном рамках, что я хочу, как это следующим образом:

template <class T, size_t N> 
struct Container { 
private: 
T containment[N]; 
public: 
T & operator[](size_t index) { return containment[index]; } 
}; 

Container<int[3][3][3],2> obj; 
obj[1][1][1][1]=7; 
5

Ваш оператор подписки должен вернуть прокси-объект, который сам будет реализовывать оператор подписки.

Если мы разложим вызов obj[2][3] = 6 это даст:

  • obj[2] -> прокси-объект
  • obj[2][6] -> ссылка на int

Глядя на obj1 вы что все, кроме последнего [], должны возвращать прокси-объект.

Это типично вниз, используя шаблонный прокси с параметром «глубина» и специализируйте его на подходящей глубине. В вашем случае ваш прокси будет иметь указатель на T для первого элемента, который он может дать, а также список измерений (в качестве параметров шаблона).

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

+0

проверить мой собственный ответ. – Pooria 2010-11-22 17:57:23

3

Вы можете сделать это примерно так (новый шаблон для каждой размерности).

template <class T, size_t m, size_t n> 
struct Container{ 
public: 
    int& operator()(size_t i, size_t j) 
    { 
     return containment[i][j]; 
    } 

private: 
    T containment[m][n]; 
}; 

Container<int, 3, 4> ints; 
ints(0,3) = 5; 

Или вы могли бы использовать Boost.MultiArray, и сэкономить много боли.

подпиточного библиотека MultiArray повышает C++ стандартные контейнеры с разносторонних многомерный массив абстракций. Он включает в себя общий шаблон класса массива и собственный массив адаптеры, которые поддерживают идиоматический массив операций и взаимодействуют с C++ Стандартные библиотечные контейнеры и алгоритмы. Массивы имеют общий интерфейс , выраженный в виде общего программирования , в котором могут быть реализованы алгоритмы массива .

+0

Одной из проблем с этим дизайном является то, что каждый шаблон должен иметь новое имя, потому что вы не можете специализироваться с другой реальностью. Общим решением является наличие фиктивных параметров (со значениями по умолчанию). Хороший призыв к Boost.MultiArray, помимо использования одного себя, лучше всего использовать существующие решения :) – 2010-11-22 17:38:39

+0

@Matthieu - да, также это не позволяет `operator [] []` нотации без дополнительной работы. Я мог бы, вероятно, терпеть боль «Array2D», «Array3D» и т. Д. Как я мог терпеть боль не используя «Boost.MultiArray», хотя, зная, что это там? – 2010-11-22 17:43:45

+0

Как я уже говорил в своем предыдущем, если не кодировать упражнение, нет смысла изобретать колесо, что я оставил этот ответ :) – 2010-11-22 17:52:46

2

Сложность заключается в знании типа возврата operator[].Вы могли бы попробовать что-то вроде этого:

template <class T, size_t N> 
struct Container { 
T containment[N]; 
T &operator[](size_t index) { return containment[index]; } 
}; 

Container<int[2][6], 5> obj; 

В качестве альтернативы можно определить контейнер с точки зрения само по себе:

Container<Container<Container<int[6]>[2]>[5]> obj; 
0

Основы создания п-мерного сбора будет что-то вроде этого. Предполагается, что контейнер не может быть перенастроен.

template< typename T > 
class MultiDimContainer 
{ 
    std::vector<size_t> dims; 

    std::vector<T> data; 

public: 
    MultiDimContainer(const std::vector<size_t> dims) 
    { 
     // work out the product of dims and set data to that size 
    } 

    T& at(const std::vector<size_t> & dim) 
    { 
     // calculate where it lives in memory and return that element 
    } 
}; 

Как я применил в() для принятия единственного параметра, для этого можно использовать оператор []. Вам, вероятно, понадобится 2 перегрузки, одна константа и одна неконстантная, а в() будут проверяться границы, пока оператор [] не будет. Вероятно, вам понадобится одна вспомогательная (не шаблонная) функция для вычисления местоположения этого элемента в вашем векторе данных.

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

Вы также можете иметь оператор [] для вашего контейнера, который возьмет один размер_t и вернет объект ContainerReferencer. Это не реальный многомерный массив, а фрагмент данных, хранящихся в других местах. Еще раз могут быть константные или неконстантные версии.

Получение множественных вызовов оператора [] для фильтрации до значения типа T или ссылки на него невозможно с использованием этой модели.

Было бы возможно использование жесткого массива, который мог бы быть параметром шаблона. Так что, если вы знаете, что это 4-х размеров вы могли бы назвать его

< MultiDimCollection двойной, 4>

и он всегда будет иметь 4 измерения. Затем вы можете получить оператор [], чтобы вернуть MultiDimCollectionReference < double, 3>

это будет идти до 2 и 1 (вектор), тогда это будет специализировано для возврата скаляра.

Смежные вопросы