Topic: iterator_traits vs. back_insert_iterator


Author: dave@boost-consulting.com (David Abrahams)
Date: Wed, 14 Sep 2005 05:33:35 GMT
Raw View
imre.palik.ext@automation.siemens.com (Palik Imre) writes:

> Hi y'all,
>
> According to my copy of the standard, the definition of the
> back_inserter_iterator starts as
>
> template <class Container>
> class back_insert_iterator : public iterator<output_iterator_tag,void,void,void,void> {
>
> accidentaly this means
> iterator_traits<back_insert_iterator<Container> >::value_type
> is always void.

It's not an accident.

> I guess, this makes it pretty unsuitable for algorithms
> that are somehow depending on the output type.
>
> Is this a bug in the standard, or there are some deep thoughts behind it?

Well, the whole area of iterators' associated types is underspecified
in the standard, but this is not a bug.  Output iterators have a _set_
of value types, so choosing a particular value_type may not make
sense.  According to 24.3.1,

  In the case of an output iterator, the types
  iterator_traits<Iterator>::difference_type
  iterator_traits<Iterator>::value_type are both defined as void.


--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: bop@gmb.dk ("Bo Persson")
Date: Wed, 14 Sep 2005 05:35:14 GMT
Raw View
"Palik Imre" <imre.palik.ext@automation.siemens.com> skrev i
meddelandet news:amfysabqth.fsf@automation.siemens.com...
> Hi y'all,
>
> According to my copy of the standard, the definition of the
> back_inserter_iterator starts as
>
> template <class Container>
> class back_insert_iterator : public
> iterator<output_iterator_tag,void,void,void,void> {
>
> accidentaly this means
> iterator_traits<back_insert_iterator<Container> >::value_type
> is always void.  I guess, this makes it pretty unsuitable for
> algorithms
> that are somehow depending on the output type.
>
> Is this a bug in the standard, or there are some deep thoughts
> behind it?
>

You cannot access the element after it is output (like printed!), so
its exact type is not interesting.

The only requirement is that

*iter = element;

will work.


Bo Persson


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kuyper@wizard.net
Date: 14 Sep 2005 05:40:06 GMT
Raw View
Palik Imre wrote:
> Hi y'all,
>
> According to my copy of the standard, the definition of the
> back_inserter_iterator starts as
>
> template <class Container>
> class back_insert_iterator : public iterator<output_iterator_tag,void,void,void,void> {
>
> accidentaly this means
> iterator_traits<back_insert_iterator<Container> >::value_type
> is always void.  I guess, this makes it pretty unsuitable for algorithms
> that are somehow depending on the output type.
>
> Is this a bug in the standard, or there are some deep thoughts behind it?

std::back_insert_iterator<Container> is for inserting things into the
container. It's an output iterator. It isn't supposed to be used in
contexts where you need to retrieve a value, rather than write one. The
standard explicitly states that
std::iterator_traits<Iterator>::value_type is supposed to be void for
output iterators (24.3.1p1).

For an output iterator 'a', the only thing you're guaranteed to be
allowed to do with *a is to assign a T object into the result:

        *a = t;

This could be achieved by giving *a a type of T&, and that's often true
for output iterators that are also input iterators. However, for a pure
output iterator it's possible for *a to return a class type for which
operator=(const T&) is defined.

That's exactly what back_insert_iterator<Container> does: operator*()
returns back_insert_operator&, and operator=(typename
Container::const_reference) performs the actual insertion.

If you're using an algorithm with an output iterator, that algorithm
has to be writing something to that output iterator (usually from an
input iterator). If the algorithm needs a value type to use for
intermediate steps, it can use

typename std::iterator_traits<InputIterator>::value_type

If that won't work with the output iterator, then the algorithm doesn't
make sense for that pair of iterator types.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: imre.palik.ext@automation.siemens.com (Palik Imre)
Date: Wed, 14 Sep 2005 14:26:49 GMT
Raw View
bop@gmb.dk ("Bo Persson") writes:

> "Palik Imre" <imre.palik.ext@automation.siemens.com> skrev i
> meddelandet news:amfysabqth.fsf@automation.siemens.com...
>
> You cannot access the element after it is output (like printed!), so
> its exact type is not interesting.
>
> The only requirement is that
>
> *iter = element;
>
> will work.

In my case, allowing this assignability in the given algorithm, would
interfere with  other parts of the program.  Actually I had something like
this in mind:

template<typename InputIterator, typename OutputIterator, typename BinaryOperation>
OutputIterator
partialSum(InputIterator first, InputIterator last,
            OutputIterator result, BinaryOperation binaryOp)
{
    typedef typename std::iterator_traits<OutputIterator>::value_type ValueType;
    if (first == last) return result;
    ValueType value = ValueType();
    while (first != last)
    {
 value = binaryOp(value, *first);
 *result++ = value;
        first++;
    }
    return ++result;
}

Thanks,

ImRe

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: bop@gmb.dk ("Bo Persson")
Date: Wed, 14 Sep 2005 23:22:26 GMT
Raw View
"Palik Imre" <imre.palik.ext@automation.siemens.com> skrev i
meddelandet news:ampsrc9mzb.fsf@automation.siemens.com...
> bop@gmb.dk ("Bo Persson") writes:
>
>> "Palik Imre" <imre.palik.ext@automation.siemens.com> skrev i
>> meddelandet news:amfysabqth.fsf@automation.siemens.com...
>>
>> You cannot access the element after it is output (like printed!),
>> so
>> its exact type is not interesting.
>>
>> The only requirement is that
>>
>> *iter = element;
>>
>> will work.
>
> In my case, allowing this assignability in the given algorithm,
> would
> interfere with  other parts of the program.  Actually I had
> something like
> this in mind:
>
> template<typename InputIterator, typename OutputIterator, typename
> BinaryOperation>
> OutputIterator
> partialSum(InputIterator first, InputIterator last,
>            OutputIterator result, BinaryOperation binaryOp)
> {
>    typedef typename std::iterator_traits<OutputIterator>::value_type
> ValueType;
>    if (first == last) return result;
>    ValueType value = ValueType();
>    while (first != last)
>    {
> value = binaryOp(value, *first);
> *result++ = value;
>        first++;
>    }
>    return ++result;
> }
>

Ok, then why don't you use the InputIterator::value_type instead? That
is the type of the values you are summing up.

The problem with an output iterator is that it may actually output the
value, like to the screen or a printer. Once it's printed, you cannot
add anything to it. :-)

You do know that there is a std::partial_sum already available in the
standard library, don't you?


Bo Persson


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kuyper@wizard.net
Date: 15 Sep 2005 05:30:05 GMT
Raw View
Palik Imre wrote:
> bop@gmb.dk ("Bo Persson") writes:
>
> > "Palik Imre" <imre.palik.ext@automation.siemens.com> skrev i
> > meddelandet news:amfysabqth.fsf@automation.siemens.com...
> >
> > You cannot access the element after it is output (like printed!), so
> > its exact type is not interesting.
> >
> > The only requirement is that
> >
> > *iter = element;
> >
> > will work.
>
> In my case, allowing this assignability in the given algorithm, would
> interfere with  other parts of the program.  Actually I had something like
> this in mind:
>
> template<typename InputIterator, typename OutputIterator, typename BinaryOperation>
> OutputIterator
> partialSum(InputIterator first, InputIterator last,
>             OutputIterator result, BinaryOperation binaryOp)
> {
>     typedef typename std::iterator_traits<OutputIterator>::value_type ValueType;

If you're willing to impose the requirement that BinaryOperation must
typedef a result_type, as would happen automatically if it derives from
std::binary_function<>, then the following would be the ideal solution:

typedef typename BinaryOperation::result_type ValueType;

Otherwise, the definition

typedef typename std::iterator_traits<InputIterator>::value_type
ValueType;

is likely to do the job in most cases.

That's not quite guaranteed. If the InputIterator's value type is A,
and the BinaryOperation's result type is B, and the OutputIterator's
value type is C, and if a value of type B can be converted to type C,
but not type A, then the following binary operator is going to cause
problems:

struct messed_up
{
B operator() (const A&, const A&) const;
B operator() (const B&, const B&) const;
};


Your function is very similar to std::partial_sum<>. By my reading of
section 26.4.3 of the C++ standard,

std::partial_sum<A_iterator, C_iterator, messed_up>()

is supposed to actually work, but I don't see how it could be written
to deal with this case.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: imre.palik.ext@automation.siemens.com (Palik Imre)
Date: Tue, 13 Sep 2005 04:18:26 GMT
Raw View
Hi y'all,

According to my copy of the standard, the definition of the
back_inserter_iterator starts as

template <class Container>
class back_insert_iterator : public iterator<output_iterator_tag,void,void,void,void> {

accidentaly this means
iterator_traits<back_insert_iterator<Container> >::value_type
is always void.  I guess, this makes it pretty unsuitable for algorithms
that are somehow depending on the output type.

Is this a bug in the standard, or there are some deep thoughts behind it?

Thx.

ImRe

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]