The STL commonly defines an output iterator like so:
template<class Cont>
class insert_iterator
: public iterator<output_iterator_tag,void,void,void,void> {
// ...
Why do output iterators define value_type as void? It would be useful for an algorithm to know what type of value it is supposed to output.
For example, a function that translates a URL query "key1=value1&key2=value2&key3=value3" into any container that holds key-value strings elements.
template<typename Ch,typename Tr,typename Out>
void parse(const std::basic_string<Ch,Tr>& str, Out result)
{
std::basic_string<Ch,Tr> key, value;
// loop over str, parse into p ...
*result = typename iterator_traits<Out>::value_type(key, value);
}
The SGI reference page of value_type hints this is because it’s not possible to dereference an output iterator. But that’s not the only use of value_type: I might want to instantiate one in order to assign it to the iterator.
What alternative approach is there for constructing a value to output with the output iterator? Two approaches I considered:
- Accept a functor parameter that would return an object of the correct type. I still want to have a version of the algorithm that doesn’t take that function object parameter though.
- Require that the output container holds
pair<string,string>, or else a type convertible from that. I wonder if I can do without this requirement, perhaps allow any element that can construct from twostd::strings.
The real value type of the iterator could well be the iterator itself.
operator*may easily just return a reference to*thisbecause the real work is done by the assignment operator. You may well find that*it = x;andit = x;have exactly the same effect with output iterators (I suppose special measures might be taken to prevent the latter from compiling).As such, defining the real value type would be just as useless. Defining it as a
void, on the other hand, can prevent errors like:I suppose this is just the limit of the concept of output iterators: they are objects which “abuse” operator overloading, so as to appear pointerlike, whereas in reality something completely different is going on.
Your problem is interesting, though. If you want to support any container, then the output iterators in question would probably be
std::insert_iterator,std::front_insert_iteratorandstd::back_insert_iterator. In this case you could do something like the following:It would still only get you this far. I suppose one could take this further, so it can also manage, say, a
std::ostream_iterator<printable_type>, but at some point it would get so complex that it takes a god to decipher the error messages, should something go wrong.