Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why the value_type/difference_type/pointer/reference of back_insert_iterator/front_insert_iterator/insert_iterator are all void?

Tags:

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.

like image 366
Yun Huang Avatar asked Apr 23 '13 09:04

Yun Huang


2 Answers

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.

like image 53
Luc Touraille Avatar answered Sep 24 '22 14:09

Luc Touraille


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 ) );
like image 29
indeterminately sequenced Avatar answered Sep 21 '22 14:09

indeterminately sequenced