Можно ли получить тип значения из произвольного итератора (С++)?

У меня есть класс

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) не будет компилироваться.