В выходные я снова работал с C ++ и заметил, что я не уверен, откуда он.
Следуя советам в этой теме , я решил реализовать map_keys_iterator
и map_values_iterator
. Я выбрал (я думаю) рекомендованный метод извлечения класса из std::map<K,V>::iterator
и реализовал его так:
template <typename K, typename V>
struct map_values_iterator:
public std::map<K,V>::iterator {
// explicitly call base's constructor
typedef typename std::map<K,V>::iterator mIterator;
map_values_iterator (const mIterator& mi) :
mIterator(mi) {};
const V& operator* () const { return (*this)->second; }
};
Пока все хорошо, и работает следующий код (nvm Unicode, я по умолчанию работаю с терминалами с поддержкой i18n):
typedef std::map<double,string> Map;
Map constants;
constants[M_PI] = "π";
constants[(1+sqrt(5))/2] = "φ";
constants[exp(M_PI)-M_PI] = "fake_20";
// ... fill map with more constants!
map_values_iterator<double, std::string> vs(constants.begin());
for (; vs != m.end(); ++vs) {
cout<< (vs != m.begin() ? ", " : "")<< *vs;
}
cout<< endl;
Этот код печатает ожидаемый результат, что-то вроде (потому что элементы карты упорядочены):
..., φ, ..., π, ...., fake_20, ....
Так что, я думаю, map_keys_iterator
будет работать аналогичным образом. Я позаботился о том, чтобы тип_значения Карты на самом деле был pair<const K, V>
, поэтому версия keys вернет значение.
Тем не менее, громоздко нужно объявлять тип итератора, поэтому я хотел создать вызывающую сторону с классической make_pair
-подобной идиомой. И вот тут начинается беда:
template <typename K, typename V>
map_values_iterator<K,V> map_values(const typename std::map<K,V>::iterator &i) {
return lpp::map_values_iterator<K,V> (i);
}
template <typename K, typename V>
map_values_iterator<K,V> map_values(const typename std::map<K,V>::const_iterator &i) {
return lpp::map_values_iterator<K,V> (i);
}
Я относительно уверен, что эта функция имеет правильную сигнатуру и вызов конструктора. Однако, если я попытаюсь вызвать функцию из кода:
auto vs= map_values(constants.begin());
Я получаю одну ошибку компилятора STL в форме:
error: no matching function for call to ‘map_values(std::_Rb_tree_iterator<std::pair<const double, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >)’
Я предполагаю, что в данном конкретном случае весь _Rb_tree_iterator
на самом деле является правильным итератором, для которого map::iterator
определен с помощью типа; Я не совсем уверен, однако. Я пытался предоставить больше перегрузок, чтобы увидеть, соответствует ли один из них (удалить ссылку, удалить const, использовать только варианты не-const_iterator и т. Д.), Но пока что ничто не позволяет использовать интересующую меня сигнатуру.
Если я сохраню базовый итератор в переменной перед вызовом функции (как в auto begin= constans.begin(); auto vs= map_values(begin);
), я получу точно такую же базовую ошибку, очевидно, отличается только описание несопоставленного вызова (в том смысле, что это "const blah & «).
Моей первой попыткой реализации такого рода итераторов было создание базового класса, который агрегирует map::iterator
вместо наследования, и получение двух классов, каждый с адекватным operator*
, но эта версия столкнулась с гораздо большим количеством проблем, чем выше и по-прежнему вынуждает меня копировать слишком много интерфейса. Поэтому я попробовал эту опцию для кода-экспедиции.
Я пытался найти ответы на этот вопрос, но мой Google-фу сегодня не очень силен. Может быть, я упускаю что-то очевидное, может быть, я что-то забыл с деривацией (хотя я почти уверен, что не сделал этого - итераторы не похожи на контейнеры), возможно, мне действительно нужно указать все параметры шаблона для карты, или, может быть, мой компилятор сломан, но что бы это ни было, я не могу его найти, и мне очень трудно понять, о чем фактическая вещь, на которую здесь жалуется компилятор. По моему предыдущему опыту, если вы делаете что-то не так с STL, вы должны видеть понос ошибок, а не только one (который не является STL для загрузки).
Так что ... любые (хорошо инкапсулированные) указатели приветствуются.