Произведите value_type итератора

STL обычно определяет выходной итератор как так:

template
class insert_iterator
: public iterator {
    // ...

Почему произведенные итераторы определяют value_type как void? Для алгоритма было бы полезно знать, какое значение это, как предполагается, производит.

Например, функция, которая переводит запрос URL "key1=value1&key2=value2&key3=value3" в любой контейнер, который содержит значение ключа, представляет элементы в виде строки.

template
void parse(const std::basic_string& str, Out result)
{
    std::basic_string key, value;
    // loop over str, parse into p ...
        *result = typename iterator_traits::value_type(key, value);
}

Ссылочная страница SGI value_type подсказки, которые это вызвано тем, что не возможно разыменовать выходной итератор. Но это не единственное использование value_type: Я мог бы хотеть инстанцировать того для присвоения его итератору.

Что альтернативный подход там для построения значения для вывода с выходным итератором? Два подхода я рассмотрел:

  • Примите параметр функтора, который возвратил бы объект корректного типа. Я все еще хочу иметь версию алгоритма, который не берет тот параметр функционального объекта все же.
  • Потребуйте, чтобы выходной контейнер содержал pair, или иначе тип, конвертируемый от этого. Интересно, могу ли я обойтись без этого требования, возможно, позволить какой-либо элемент, который может создать от два std::string s.

22
задан wilhelmtell 12 April 2010 в 03:53
поделиться

2 ответа

Типом реального значения итератора вполне может быть сам итератор. Оператор * может легко вернуть ссылку на * this , потому что реальная работа выполняется оператором присваивания. Вы вполне можете обнаружить, что * it = x; и it = x; имеют точно такой же эффект с итераторами вывода (я предполагаю, что могут быть приняты специальные меры для предотвращения компиляции последнего) .

Таким образом, определение реального типа значения было бы бесполезным. С другой стороны, определение его как void может предотвратить такие ошибки, как:

 typename Iter::value_type v = *it; //useless with an output iterator if it compiled

Я полагаю, что это всего лишь предел концепции итераторов вывода: они являются объектами, которые «злоупотребляют» перегрузкой оператора, поэтому Что касается , то они выглядят как указатели, тогда как на самом деле происходит нечто совершенно иное.

Но ваша проблема интересная. Если вы хотите поддерживать какой-либо контейнер, то рассматриваемые итераторы вывода, вероятно, будут std :: insert_iterator , std :: front_insert_iterator и std :: back_insert_iterator . В этом случае вы можете сделать что-то вроде следующего:

#include <iterator>
#include <vector>
#include <string>
#include <map>
#include <iostream>

//Iterator has value_type, use it
template <class T, class IterValue>
struct value_type
{
    typedef IterValue type;
};

//output iterator, use the container's value_type
template <class Container>
struct value_type<Container, void>
{
    typedef typename Container::value_type type;
};

template <class T, class Out>
void parse_aux(Out out)
{
    *out = typename value_type<T, typename Out::value_type>::type("a", "b");
}

template <template <class> class Out, class T>
void parse(Out<T> out)
{
    parse_aux<T>(out);
}

//variadic template in C++0x could take care of this and other overloads that might be needed
template <template <class, class> class Out, class T, class U>
void parse(Out<T, U> out)
{
    parse_aux<T>(out);
}

int main()
{
    std::vector<std::pair<std::string, std::string> > vec;
    parse(std::back_inserter(vec));
    std::cout << vec[0].first << ' ' << vec[0].second << '\n';

    std::map<std::string, std::string> map;
    parse(std::inserter(map, map.end()));
    std::cout << map["a"] << '\n';

    //just might also support normal iterators
    std::vector<std::pair<std::string, std::string> > vec2(1);
    parse(vec2.begin());
    std::cout << vec2[0].first << ' ' << vec2[0].second << '\n';
}

Это все равно приведет вас только к этому.Я полагаю, что можно пойти дальше, так что он также может управлять, скажем, std :: ostream_iterator , но в какой-то момент это станет настолько сложным, что потребуется бог, чтобы расшифровать сообщения об ошибках , если что-то пойдет не так.

10
ответ дан 29 November 2019 в 05:54
поделиться

Назначение value_type итератора - определить тип, который возвращается при разыменовании итератора. Для выходных итераторов единственное законное использование оператора разыменования - это когда он используется вместе с оператором присваивания - в форме *output_iterator = value. Тип, возвращаемый при разыменовании выходного итератора, не обязательно имеет прямую связь с типами, которые могут быть сохранены через выходной итератор. Единственная необходимая связь - это наличие некоторого способа присвоения последних типов первому типу.

Более того, выходной итератор может хранить значения нескольких типов, и эти типы не обязательно должны быть связаны друг с другом. Возьмем, например, null_output_iterator, описанный в Discarding the output of a function that needs an output iterator. Этот итератор может принимать на хранение значения любого типа.

2
ответ дан 29 November 2019 в 05:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: