Можно ли получить тип значения из произвольного итератора (С++)?
У меня есть класс
template <typename Iterator, typename Value>
class Foo {
public:
Foo(const Iterator& it) { ... }
...
private:
map<Value, int> m_;
}
};
Есть ли способ избавиться от значения в шаблоне? Итератор может быть или не быть итератором STL, но он гарантировал, что * это тип Value.
Я знаю о iterator_traits<T>::value_type
для итераторов STL, но задаюсь вопросом, есть ли способ получить тип значения автоматически для любого типа Iterator?
Один трюк, о котором я думаю - скажем, у нас есть вспомогательный класс
template <typename Iterator, typename Value>
class Bar {
public:
Bar(const Iterator& dummy_iterator, const Value& dummmy_value) {}
...
};
Тогда, если мы создадим Bar как Bar (it, * it), тип Value будет известен внутри Bar. Но я не могу найти хороший способ комбинировать Bar с Foo.
Ответы
Ответ 1
Любой итератор должен предоставить iterator_traits<Iterator>::value_type
. Если это не так, то это не итератор. ISO С++ 2003 24.3.1 [lib.iterator.traits] "Итераторные черты":
Использовать алгоритмы только в терминах итераторов, часто необходимо определить значение и разницу типы, которые соответствуют конкретному тип итератора. Соответственно, что если Iterator
- тип итератора, типы
iterator_traits<Iterator>::difference_type
iterator_traits<Iterator>::value_type
iterator_traits<Iterator>::iterator_category
определяется как итераторы тип разности, тип значения и итератора соответственно.
Кроме того, нет общего способа получения типа произвольного выражения С++. С++ 0x исправит его, предоставив decltype
.
Ответ 2
К сожалению. Правильный способ избавиться от Value
- это использовать iterator_traits
, как вы предполагали.
Если ваш не-STL-итератор - голый указатель, вы получите правильное iterator_traits typedefs бесплатно. В противном случае класс itter не-STL должен определять правильные typedefs.
Подробнее см. документацию итератора.
Ответ 3
Что касается получения типа значения итератора, то предыдущие ответы были правильными.
Но есть еще. Трюк, о котором вы думаете, не будет работать с классом. Если Bar
была функцией вроде:
template <typename Iterator, typename Value>
void bar(const Iterator& dummy_iterator, const Value& dummmy_value) {}
тогда тип вывода будет работать для bar(it, *it)
, и у вас будет тип значения внутри Bar
. (Но имейте в виду, что для использования этого трюка вам все равно придется иметь неразрешимый итератор, который не всегда хорош - как иметь дело с пустой последовательностью?)
Используя класс Bar
, вам нужно будет предоставить аргументы шаблона Iterator
и Value
вручную, так как для классов не существует никакого вывода типа, а использование bar(it, *it)
не будет компилироваться.