In my project, I want to split stream into some given type of values, so I implement a template function as

template <typename TElem, typename TOutputIter>
TOutputIter SplitSpace(std::istream& IS, TOutputIter result)
{
    TElem elem;
    while (IS >> elem)
    {
        *result = elem;
        ++result;
    }
    return result;
}

I think this is awkward since I have to explicitly given the type of TElem when calling it. For example, I have to write:

std::vector<int> v;
SplitSpace<int>(std::cin, back_inserter(v));
// I want to it to be   SplitSpace(std::cin, back_inserter(v)); 

I tried to obtain the value type from an (template) iterator and used std::iterator_traits as follows:

template <typename TOutputIter>
TOutputIter SplitSpace(std::istream& IS, TOutputIter result)
{
    typename std::iterator_traits<TOutputIter>::value_type elem;
    while (IS >> elem)
    {
        *result = elem;
        ++result;
    }
    return result;
}

However, the above codes do not work for back_insert_iterator. I checked the source codes of back_insert_iterator/front_insert_iterator/insert_iterator in std namespace and found the value_type/difference_type/pointer/reference are all void.

I would like to know why these types are all void, is there any consideration for this? Another question is that is it possible to implement the SplitSpace function without explicitly giving the element type when call it? Thanks.

4

There are 4 best solutions below

4
On

AFAIK, you should be able to obtain the container_type from the iterator, from which you should be able to obtain a value_type. You probably want to specialize for a pair at some point. This should answer part two, as for part one; not sure...

0
On

As mentioned by Luc in the comments what you want to do can be easily done with the standard library:

std::vector<int> v;
std::copy( std::istream_iterator( std::cin )
         , std::istream_iterator()
         , std::back_inserter( v ) );
0
On

value_type does not make much sense in the case of OutputIterators, because an output iterator does not give access to any values, and more importantly it can accepts a wide range of value types.

The only requirement for an OutputIterator it is that it must supports the expression *it = o where o is a value of some type that is in the set of types that are writable to the particular iterator type of i (§24.2.1). This means that an output iterator can potentially accepts a wide range of types: for instance, its operator* can return a proxy object that overloads operator= for a variety of types ; what should be value_type in this case?

For instance, consider the following output iterator:

struct SwallowOutputIterator : 
    public std::iterator<output_iterator_tag, void, void, void, void>
{
    struct proxy // swallows anything
    {
        template <typename T>
        void operator=(const T &) {}
    };

    proxy operator*() 
    {
        return proxy();
    }

    // increment operators
};

There is no sensible choice for value_type here.

The same reasoning applies to pointer and reference_type. difference_type is not defined because you cannot calculate the distance between two output iterators, as they are single-pass.

N.B.: the standard explicitely states that insert_iterator and its siblings must inherits from iterator<output_iterator_tag, void, void, void, void>, so this is not a peculiarity of your implementation.

0
On

In case you are just looking for a way to avoid to specify the TElem template param, you can use this approach:

template <typename TOutputIter>
TOutputIter SplitSpace(std::istream& IS, TOutputIter result)
{
    typedef typename TOutputIter::container_type::value_type TElem;

    TElem elem;
    while (IS >> elem)
    {
        *result = elem;
        ++result;
    }
    return result;
}

...of course, depending on which TOutputIter types you pretend to use, you shouldn't use this approach.