Реальным типом значения итератора вполне может быть сам итератор. operator*
может легко просто вернуть ссылку на *this
, потому что реальная работа выполняется оператором присваивания. Вы можете обнаружить, что *it = x;
и it = x;
имеют одинаковый эффект с итераторами вывода (я полагаю, что могут быть предприняты специальные меры для предотвращения компиляции последних).
Таким образом, определение типа реального значения было бы столь же бесполезным. С другой стороны, определение его как void
может предотвратить такие ошибки, как:
typename Iter::value_type v = *it; //useless with an output iterator if it compiled
Я полагаю, что это только предел концепции выходных итераторов: они являются объектами, которые "злоупотребляют" перегрузкой операторов, так что кажутся указательными, тогда как в действительности происходит нечто совершенно иное. 1013 *
Твоя проблема интересная. Если вы хотите поддерживать какой-либо контейнер, то рассматриваемые выходные итераторы, вероятно, будут 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<printable_type>
, но в какой-то момент он станет настолько сложным, что потребуется бог, чтобы расшифровать сообщения об ошибках, если что-то пойдет не так.