оператор перегрузки c ++ [] для std :: pair - PullRequest
3 голосов
/ 02 марта 2012

Я много работаю с парами значений: std::pair<int, int> my_pair.Иногда мне нужно выполнить одну и ту же операцию как на my_pair.first, так и на my_pair.second.

. Мой код был бы намного более плавным, если бы я мог выполнить my_pair[j] и выполнить цикл по j = 0,1 * 1008.*.(Я избегаю использования массивов, потому что я не хочу беспокоиться о выделении памяти, и я широко использую pair с другими вещами).

Таким образом, я бы хотел определить operator[] для std::pair<int, int>.

И я не могу заставить его работать, (я не очень хорош с шаблонами и тому подобным) ...

#include <utility>
#include <stdlib.h>

template <class T1> T1& std::pair<T1, T1>::operator[](const uint &indx) const
{
  if (indx == 0)
    return first;
  else
    return second;
};

int main()
{
// ....
return 0;
}

не компилируется,Другие варианты тоже терпят неудачу.

Насколько я могу судить, я следую за часто задаваемыми вопросами по переполнению стека переполнения оператора *1024*, но, думаю, что-то упустил ...

Ответы [ 3 ]

7 голосов
/ 02 марта 2012
  1. вы не можете перегрузить оператор [] как не член
  2. вы не можете определить функцию-член, которая не была объявлена ​​в определении класса
  3. вы не можете изменить определение классаиз std :: pair

Вот реализация, не являющаяся членом:

/// @return the nth element in the pair. n must be 0 or 1.
template <class T>
const T& pair_at(const std::pair<T, T>& p, unsigned int n)
{
    assert(n == 0 || n == 1 && "Pair index must be 0 or 1!");
    return n == 0 ? p.first: p.second;
}

/// @return the nth element in the pair. n must be 0 or 1.
template <class T>
T& pair_at(std::pair<T, T>& p, unsigned int index)
{
    assert(index == 0 || index == 1 && "Pair index must be 0 or 1!");
    return index == 0 ? p.first: p.second;
}

// usage:
pair<int, int> my_pair(1, 2);
for (int j=0; j < 2; ++j)
    ++pair_at(my_pair, j);

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

Не бойтесь свободно использовать функции, не являющиеся членами.Как сказал сам Страуструп, нет необходимости моделировать все с помощью объекта или дополнять все путем наследования.Если вы хотите использовать классы, предпочтите композицию наследованию.

Вы также можете сделать что-то вроде этого:

/// Applies func to p.first and p.second.
template <class T, class Func>
void for_each_pair(const std::pair<T, T>& p, Func func)
{
    func(p.first);
    func(p.second);
}

/// Applies func to p.first and p.second.
template <class T, class Func>
void for_each_pair(std::pair<T, T>& p, Func func)
{
    func(p.first);
    func(p.second);
}

// usage:
pair<int, int> my_pair(1, 2);
for_each_pair(my_pair, [&](int& x){
    ++x;
});

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

2 голосов
/ 02 марта 2012

Вы не можете добавлять функции в существующий класс, как этот.И вы, конечно, не можете делать это с вещами в пространстве имен std.

Поэтому вы должны определить свой собственный класс-оболочку:

class MyPair {
private:
    std::pair<int,int> p;

public:
    int &operator[](int i) { return (i == 0) ? p[0] : p[1]; }
    // etc.
};
0 голосов
/ 02 марта 2012

Вы, вероятно, должны проверить Boost.Fusion .Вы можете применять алгоритмы к последовательностям (которые std :: pair считается последовательностью).Например, вы можете сделать for_each следующим образом:

std::pair<int, int> my_pair;
for_each(my_pair, [] (int i)
{
    cout << i;
});

Вы также можете получить доступ к индексу элемента следующим образом:

int sum = at_c<0>(my_pair) + at_c<1>(my_pair);
...