Можно ли разыграть пару?к паре? - PullRequest
5 голосов
/ 29 ноября 2011

Итак, у меня есть умный итератор, который эмулирует карту const_iterator, и он должен создать тип возвращаемого значения внутри.Очевидно, я хотел бы сохранить pair<Key, Value> в своем классе итераторов (поскольку мне нужно его изменить), но в то же время я бы хотел, чтобы функции разыменования представляли pair<const Key, Value> (на самом деле это было бы const pair<const Key, Value>& и const pair<const Key, Value>* соответственно).Единственное решение, которое я нашел до сих пор, - это динамическое выделение новой пары каждый раз, когда изменяется значение, на которое указывает мой класс итератора.Излишне говорить, что это не очень хорошее решение.

Я также пытался *const_cast<const pair<const Key, Value> >(&value), где value объявлен как pair<Key, Value>.

Любая помощь будет принята с благодарностью (какбыло бы знание, что это не может быть сделано).

РЕДАКТИРОВАТЬ

Для любопытных: я закончил хранить pair<const Key, Value> p в моем классе итераторов.Чтобы изменить пару, я изменяю два элемента по отдельности, основываясь на базовом итераторе (map<Key, Value>::const_iterator it), const_cast ключе, чтобы его можно было изменить, например:

*const_cast<Key*>(&p.first) = it->first;
p.second = it->second;

НеРешение, которым я ужасно доволен, но оно выполняет свою работу, и методы разыменования счастливы, потому что я храню что-то правильного типа, к которому они могут обращаться.

Ответы [ 4 ]

8 голосов
/ 29 ноября 2011

Вы можете преобразовать значение типа pair<Key,Value> в pair<const Key,Value>.

Однако, внимательно прочитав вопрос, вы на самом деле спрашиваете, если при pair<Key,Value> васможет создать указатель или ссылку на pair<const Key,Value>, ссылающуюся на тот же объект.

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

Одна из возможностей - вернуть пару ссылок pair<const Key&, Value&>, созданную из пары, на которую вы хотите сослаться.

5 голосов
/ 29 ноября 2011

Да.

std::pair<int, double> p(1,2);
std::pair<const int, double> q = p;   // no problem

//q.first = 8;  // error
q.second = 9;

int b; double d;
std::pair<int &, double &> s(b,d);
std::pair<int const &, double &> t = s;  // also fine
2 голосов
/ 29 ноября 2011

Как указал Kerrek SB, вы можете построить std::pair<const Key, Value> из std::pair<Key, Value>. Тем не менее, ваш первоначальный вопрос подразумевает, что вы хотите избежать создания объектов std :: pair при каждом разыменовании вашего итератора.

К сожалению, нет хорошего способа сделать это. Возможно, вам придется сконструировать объект пары и фактически сохранить его где-нибудь, особенно для operator->. В противном случае вы должны иметь возможность хранить на своей карте pair<const Key, Value>, чтобы иметь возможность возвращать ссылки / указатели на нее из вашего итератора. По сути, чтобы вернуть ссылку / указатель, она должна храниться где-то в этой форме: она не может быть временной.

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

0 голосов
/ 27 октября 2015

Я встретил точно такую ​​же проблему.Мое решение состояло в том, чтобы создать новый объект карты как часть класса итератора, затем добавить к нему элементы, которые отсутствуют в вышестоящем классе карты, и вернуть ссылку на его члены.Не очень эффективно, но работает.

Ваше решение имеет две проблемы:

  1. Назначение переменной const с помощью const_cast - неопределенное поведение.Оптимизация компилятора может дать странные результаты.
  2. Любая новая разыменование аннулирует результаты предыдущей разыменования.Так не должно быть.Поэтому, в зависимости от использования вашего итератора, он также может давать странные результаты.
...