Re: lvalue required as increment operand -- why does the Standard
requires this for fundamental types only?
On 3 Jul., 20:51, Pavel wrote:
[...]
template <class C> void foo(C &c) {
assert(!c.empty());
typename C::iterator lastElemIter = --c.end();
... // use lastElemIter here
}
would give me an iterator to the last element. It works if the iterator's
implementation happen to be a class
Not necessarily. operator-- could be implemented as a free function
taking an lvalue reference parameter. And it would be ok to do so
because the ITERATOR CONCEPT only requires ++ and -- (for
bidirectional iterators) to work on LVALUES. We have interfaces for a
reason. Don't rely on specific implementations!
On 3 Jul., 21:12, Pavel wrote:
SG wrote:
template<class Iter>
inline Iter next(Iter it) { std::advance(it,1); return it; }
This is essentially what I need semantically. Performance-wise, however, =
I want
to avoid std::advance, because it may be and often is less efficient for =
many
iterators (e.g. list or map iterators -- which are usually class object a=
nd for
which ++ would work).
These are bidirectional iterators. For such iterators std::advance
maps to something like this via tag dispatching:
template<class Iter>
inline void advance_(
Iter & it,
typename iterator_traits<Iter>::difference_type d,
bidirectional_iterator_tag)
{
if (d<0) {
while (d++ < 0) --it;
} else {
while (d-- > 0) ++it;
}
}
Compared to ++it, advance(it,1) only requires two additional tests --
that is, unless the compiler inlines this function and applies some
dead branch elimination because the value d is known to be 1 at
compile time during inlining.
Of course, why write advance(it,1) if you can write ++it directly? I
don't know. That's just how the upcoming standard describes the
behaviour of std::next. I guess implementers will simply write this
template<class Iter>
inline Iter next(Iter x) { ++x; return x; }
considering the "as-if rule".
And just for the fun of it, let's ACTUALLY test how G++ optimizes
advance with a constant second parameter of value 1 for list
iterators:
#include <iterator>
#include <list>
typedef std::list<int>::iterator iter;
iter next(iter it) {
std::advance(it,1);
return it;
}
--[ g++ -O3 advance.cpp && objdump -Cd advance.o ]-->
00000000 <next(std::_List_iterator<int>)>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 8b 45 08 mov 0x8(%ebp),%eax
6: 8b 00 mov (%eax),%eax
8: c9 leave
9: c3 ret
a: 90 nop
b: 90 nop
I see no loop, no tests of any kind. In fact, when I replace
advance(it,1) with ++it, I see EXACTLY the same assembly code.
Hmm.... :-D
Cheers!
SG