Ответ 1
Реальный тип значения итератора вполне может быть итератором. operator*
может просто просто вернуть ссылку на *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 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>
, но в какой-то момент он будет настолько сложным, что требуется, чтобы бог расшифровал сообщения об ошибках, если что-то пойдет не так.