lvalue required as increment operand -- why does the Standard requiresthis for fundamental types on

Discussion in 'C++' started by Pavel, Jul 2, 2011.

  1. Pavel

    Pavel Guest

    In the code below, the increment on a function call expression of type "int"
    does not compile but the one on a function call expression of class Int compiles
    fine. My understanding is (please correct me if I am wrong) that it directly
    follows from 3.10 and 5.3-2 of the current Standard and (also please correct me
    if I am wrong here) that this is no different in the upcoming C++0x Standard.

    What is the rationale for this lvalue requirement if there is one?

    My suspicion is that it may be related to an optimization opportunity for a C++
    compiler but I could not come up with a satisfactory guess on what it could be.
    To rephrase my question, am I writing a potentially sub-optimal code if I always
    use a thin class wrapper around a fundamental integral or pointer type as
    opposed to using it outright? (I use a wrapper, in particular, to be able to
    call ++ on the function's return value; this is an advantage in my case -- but
    is there a downside other than having to write the wrapper?)

    TIA,
    -Pavel


    -----------------
    int f1() { return 5; }

    class Int {
    public:
    explicit Int(int i) : i_(i) {}
    Int & operator++() { ++i_; return *this; }
    private:
    int i_;
    };

    Int f2() { return Int(5); }

    int main(int, char *[]) {
    //int i1 = ++f1(); (void)i1; // this does not compile
    Int i2 = ++f2(); (void)i2; // this compiles fine
    return 0;
    }
    Pavel, Jul 2, 2011
    #1
    1. Advertising

  2. Pavel

    SG Guest

    Re: lvalue required as increment operand -- why does the Standardrequires this for fundamental types only?

    On 2 Jul., 19:30, Pavel wrote:
    >
    > What is the rationale for this lvalue requirement if there is one?
    >
    > -----------------
    > int f1() { return 5; }
    >
    > class Int {
    > public:
    >    explicit Int(int i) : i_(i) {}
    >    Int & operator++() { ++i_; return *this; }
    > private:
    >    int i_;
    > };
    >
    > Int f2() { return Int(5); }
    >
    > int main(int, char *[]) {
    > //int i1 = ++f1(); (void)i1; // this does not compile
    >    Int i2 = ++f2(); (void)i2; // this compiles fine
    >    return 0;


    Why do you even want the first one to compile? f1 simply returns a
    value. If you want f1()+1 then write f1()+1. There is abolutely no
    reason to support prefix ++ on things that don't refer to any object.
    Check the C++ standard w.r.t. the C++ object model and lvalue/rvalue
    expressions. You'll see that an rvalue of type int does NOT refer to
    an object whereas an rvalue of type Int _does_ refer to an object
    because Int is a class type. Now, why does C++ allow you to invoke a
    nonconst member function on a temporary object? Answer: Why not? It
    may be useful. Whether you overloaded an operator or wrote a function
    with some other name does not matter. Your overloaded operator++ could
    have other side effects which would make ++f2() do something useful.

    Cheers!
    SG
    SG, Jul 2, 2011
    #2
    1. Advertising

  3. Pavel

    Pavel Guest

    Re: lvalue required as increment operand -- why does the Standardrequires this for fundamental types only?

    SG wrote:
    > On 2 Jul., 19:30, Pavel wrote:
    >>
    >> What is the rationale for this lvalue requirement if there is one?
    >>
    >> -----------------
    >> int f1() { return 5; }
    >>
    >> class Int {
    >> public:
    >> explicit Int(int i) : i_(i) {}
    >> Int& operator++() { ++i_; return *this; }
    >> private:
    >> int i_;
    >> };
    >>
    >> Int f2() { return Int(5); }
    >>
    >> int main(int, char *[]) {
    >> //int i1 = ++f1(); (void)i1; // this does not compile
    >> Int i2 = ++f2(); (void)i2; // this compiles fine
    >> return 0;

    >
    > Why do you even want the first one to compile? f1 simply returns a
    > value. If you want f1()+1 then write f1()+1.

    Because in a generic algorithms, f()+1 and ++f() for some (class) types may not
    be equivalent (in particular, f() + 1 is often slower than ++f() for class
    types). I want my algo to compile on both fundamental and class types and do not
    want to sacrifice performance on class types if I do not have to. An example of
    a (class) type for which operator+(some_distance_type) and operator++() may have
    different performance is a list iterator.

    There is abolutely no
    > reason to support prefix ++ on things that don't refer to any object.

    Thanks, I knew that already. This was not not my question. The question was
    about the specific rationale for this decision of the Standard's authors.

    > Check the C++ standard w.r.t. the C++ object model and lvalue/rvalue
    > expressions. You'll see that an rvalue of type int does NOT refer to
    > an object whereas an rvalue of type Int _does_ refer to an object
    > because Int is a class type.

    Thanks, but that was not my question. I know (or I believe I know) how the
    observed behavior is compliant with the Standard. I am asking for a rationale.

    Now, why does C++ allow you to invoke a
    > nonconst member function on a temporary object?

    Thanks, it was not my question again.

    Answer: Why not? It
    > may be useful. Whether you overloaded an operator or wrote a function
    > with some other name does not matter. Your overloaded operator++ could
    > have other side effects which would make ++f2() do something useful.
    >
    > Cheers!
    > SG


    Thanks,
    -Pavel
    Pavel, Jul 2, 2011
    #3
  4. Pavel

    SG Guest

    Re: lvalue required as increment operand -- why does the Standardrequires this for fundamental types only?

    On 3 Jul., 11:52, Paavo Helde <> wrote:
    > Pavel wrote:
    > > SG wrote:
    > >> On 2 Jul., 19:30, Pavel wrote:
    > >>> What is the rationale for this lvalue requirement if there is one?
    > >> There is abolutely no reason [for C++] to support prefix ++ on things
    > >> that don't refer to any object.

    > > Thanks, I knew that already. This was not not my question. The
    > > question was about the specific rationale for this decision of the
    > > Standard's authors.

    >
    > You are missing the point.


    I have the same feeling. Maybe I left out some detail that is obvious
    to most but not Pavel.

    > Supporting ++ on non-objects is logically
    > infeasible, [...]


    ....because ++ means "increment that thing and return the new value"
    and you don't want 5 to be 6. ;-) But maybe I simply didn't get the
    question.

    As for genericity: You may implement your own iterator's prefix ++ via
    a member function. But incrementing rvalue iterators is still not part
    of the iterator concept! Otherwise, raw pointers wouldn't be
    iterators. If you want to code generically you better limit yourself
    to the concepts' interfaces.

    The standard library of the upcoming C++ ISO standard will provide two
    helper functions: prev and next after including <iterator>. Then you
    can write things like

    auto second = next(container.begin());

    if you want to. I think Boost provides something similar already and
    it's easy to do it yourself:

    template<class Iter>
    inline Iter next(Iter it) { std::advance(it,1); return it; }

    Cheers!
    SG
    SG, Jul 3, 2011
    #4
  5. Pavel

    Pavel Guest

    Re: lvalue required as increment operand -- why does the Standardrequires this for fundamental types only?

    Paavo Helde wrote:
    > Pavel<> wrote in
    > news:4e0f790a$0$21283$c3e8da3$:
    >
    >> SG wrote:
    >>> On 2 Jul., 19:30, Pavel wrote:
    >>>>
    >>>> What is the rationale for this lvalue requirement if there is one?
    >>>>
    >>>> -----------------
    >>>> int f1() { return 5; }

    > [...]
    >>>> int main(int, char *[]) {
    >>>> //int i1 = ++f1(); (void)i1; // this does not compile

    > [...]
    >>
    >> There is abolutely no
    >>> reason to support prefix ++ on things that don't refer to any object.

    >> Thanks, I knew that already. This was not not my question. The
    >> question was about the specific rationale for this decision of the
    >> Standard's authors.

    >
    > You are missing the point. Supporting ++ on non-objects is logically
    > infeasible, it's like writing "++5;" in your program. As we all know from
    > endless threads with Paul, an object is a region of memory, having a
    > certain memory address. The ++ operator would presumable update this
    > region of memory somehow, and later the changed content could be observed
    > by using the same address. If there is no memory region, what should be
    > updated? Or if you say a content of CPU register could be updated, how
    > could you refer to it afterwards to have any usage of the changes?

    I think SG knew what I wanted to do.

    say, for --:

    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 and does not if it is happen to be a
    pointer. I hope this answers yours and SC's questions on how I am to use these.

    If you know how to fix this code to compile for both class-type and
    fundamental-type iterators, without any temporary variables, if possible, I
    would appreciate your suggestion.

    This
    > would require some other language, having different rules. I think in
    > some languages one can even change the value of numeric literals ;-)
    >
    > Now if you changed f1 to read e.g.
    >
    > int& f1() { return 5; }

    I hope you see now it is not relevant to my question. I do not see any
    conceptual difference between returning structure Int consisting of a single
    integer or a bare integer, by value. Both can be and in fact are placed by
    optimizing compilers to registers. C++ Standard does say one is an rvalue
    pointing to an object and does not say it about the other; this is clearly a
    free choice of the Standard authors, not a logical consequence to anything as
    far as I can see and I would like to know the reason for this choice.

    >
    > then the functions would become more similar and we could discuss further
    > what is allowed and why.
    >
    > Cheers
    > Paavo
    >


    TIA
    -Pavel
    Pavel, Jul 3, 2011
    #5
  6. Pavel

    Pavel Guest

    Re: lvalue required as increment operand -- why does the Standardrequires this for fundamental types only?

    SG wrote:
    > On 3 Jul., 11:52, Paavo Helde<> wrote:
    >> Pavel wrote:
    >>> SG wrote:
    >>>> On 2 Jul., 19:30, Pavel wrote:
    >>>>> What is the rationale for this lvalue requirement if there is one?
    >>>> There is abolutely no reason [for C++] to support prefix ++ on things
    >>>> that don't refer to any object.
    >>> Thanks, I knew that already. This was not not my question. The
    >>> question was about the specific rationale for this decision of the
    >>> Standard's authors.

    >>
    >> You are missing the point.

    >
    > I have the same feeling. Maybe I left out some detail that is obvious
    > to most but not Pavel.
    >
    >> Supporting ++ on non-objects is logically
    >> infeasible, [...]

    >
    > ...because ++ means "increment that thing and return the new value"
    > and you don't want 5 to be 6. ;-)

    I do not think my code implies any such semantics. My f1() returns int by value.
    So it says "return a copy of this thing and then increment it".

    But maybe I simply didn't get the
    > question.
    >
    > As for genericity: You may implement your own iterator's prefix ++ via
    > a member function. But incrementing rvalue iterators is still not part
    > of the iterator concept! Otherwise, raw pointers wouldn't be
    > iterators. If you want to code generically you better limit yourself
    > to the concepts' interfaces.
    >
    > The standard library of the upcoming C++ ISO standard will provide two
    > helper functions: prev and next after including<iterator>. Then you
    > can write things like
    >
    > auto second = next(container.begin());
    >
    > if you want to. I think Boost provides something similar already and
    > it's easy to do it yourself:
    >
    > 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 and for
    which ++ would work).


    >
    > Cheers!
    > SG


    -Pavel
    Pavel, Jul 3, 2011
    #6
  7. Pavel

    Kai-Uwe Bux Guest

    Re: lvalue required as increment operand -- why does the Standard requires this for fundamental types only?

    Pavel wrote:
    > SG wrote:

    ....
    >> I think Boost provides something similar already and
    >> it's easy to do it yourself:
    >>
    >> 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 and for which ++ would work).


    Then, what about:

    template < typename Iter >
    Iter next ( Iter iter ) {
    ++ iter;
    return ( iter );
    }


    Best,

    Kai-Uwe Bux
    Kai-Uwe Bux, Jul 3, 2011
    #7
  8. Re: lvalue required as increment operand -- why does the Standardrequires this for fundamental types only?

    Le 03/07/2011 21:12, Pavel a écrit :
    > SG wrote:
    >> On 3 Jul., 11:52, Paavo Helde<> wrote:
    >>> Pavel wrote:
    >>>> SG wrote:
    >>>>> On 2 Jul., 19:30, Pavel wrote:
    >>>>>> What is the rationale for this lvalue requirement if there is one?
    >>>>> There is abolutely no reason [for C++] to support prefix ++ on things
    >>>>> that don't refer to any object.
    >>>> Thanks, I knew that already. This was not not my question. The
    >>>> question was about the specific rationale for this decision of the
    >>>> Standard's authors.
    >>>
    >>> You are missing the point.

    >>
    >> I have the same feeling. Maybe I left out some detail that is obvious
    >> to most but not Pavel.
    >>
    >>> Supporting ++ on non-objects is logically
    >>> infeasible, [...]

    >>
    >> ...because ++ means "increment that thing and return the new value"
    >> and you don't want 5 to be 6. ;-)

    > I do not think my code implies any such semantics. My f1() returns int
    > by value. So it says "return a copy of this thing and then increment it".
    >
    > But maybe I simply didn't get the
    >> question.
    >>
    >> As for genericity: You may implement your own iterator's prefix ++ via
    >> a member function. But incrementing rvalue iterators is still not part
    >> of the iterator concept! Otherwise, raw pointers wouldn't be
    >> iterators. If you want to code generically you better limit yourself
    >> to the concepts' interfaces.
    >>
    >> The standard library of the upcoming C++ ISO standard will provide two
    >> helper functions: prev and next after including<iterator>. Then you
    >> can write things like
    >>
    >> auto second = next(container.begin());
    >>
    >> if you want to. I think Boost provides something similar already and
    >> it's easy to do it yourself:
    >>
    >> 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 and for which ++ would work).
    >


    AFAIK it is not the case.
    advance(N, it) will internally call ++ N times if the operator isn't a
    random access one. So advance(1, it) should be as efficient as ++it,
    except maybe a function call, if it ever was not inlined.

    Cheers,
    Leo

    >
    >>
    >> Cheers!
    >> SG

    >
    > -Pavel
    Leo \Equinox\ Gaspard, Jul 3, 2011
    #8
  9. Re: lvalue required as increment operand -- why does the Standardrequires this for fundamental types only?

    Le 03/07/2011 20:51, Pavel a écrit :
    > Paavo Helde wrote:
    >> Pavel<> wrote in
    >> news:4e0f790a$0$21283$c3e8da3$:
    >>
    >>> SG wrote:
    >>>> On 2 Jul., 19:30, Pavel wrote:
    >>>>>
    >>>>> What is the rationale for this lvalue requirement if there is one?
    >>>>>
    >>>>> -----------------
    >>>>> int f1() { return 5; }

    >> [...]
    >>>>> int main(int, char *[]) {
    >>>>> //int i1 = ++f1(); (void)i1; // this does not compile

    >> [...]
    >>>
    >>> There is abolutely no
    >>>> reason to support prefix ++ on things that don't refer to any object.
    >>> Thanks, I knew that already. This was not not my question. The
    >>> question was about the specific rationale for this decision of the
    >>> Standard's authors.

    >>
    >> You are missing the point. Supporting ++ on non-objects is logically
    >> infeasible, it's like writing "++5;" in your program. As we all know from
    >> endless threads with Paul, an object is a region of memory, having a
    >> certain memory address. The ++ operator would presumable update this
    >> region of memory somehow, and later the changed content could be observed
    >> by using the same address. If there is no memory region, what should be
    >> updated? Or if you say a content of CPU register could be updated, how
    >> could you refer to it afterwards to have any usage of the changes?

    > I think SG knew what I wanted to do.
    >
    > say, for --:
    >
    > 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 and does not if it is
    > happen to be a pointer. I hope this answers yours and SC's questions on
    > how I am to use these.
    >
    > If you know how to fix this code to compile for both class-type and
    > fundamental-type iterators, without any temporary variables, if
    > possible, I would appreciate your suggestion.


    typename C::iterator lastElemIter = c.end(); --lastElemIter;

    No temporary variables are created, as the compiler is likely to
    optimize the return type of the function. Indeed, I believe that for
    class types the second one is even more efficient, as it could use only
    move-constructor, whereas yours implies a move and a copy constructor.

    However, I believe the compiler would optimize all of it so the two
    expressions would act the same way - except that "mine" would work with
    any iterator type.

    And std::prev(it) (or boost::prior(it)) would also do as you want.

    Cheers,
    Leo

    >
    > This
    >> would require some other language, having different rules. I think in
    >> some languages one can even change the value of numeric literals ;-)
    >>
    >> Now if you changed f1 to read e.g.
    >>
    >> int& f1() { return 5; }

    > I hope you see now it is not relevant to my question. I do not see any
    > conceptual difference between returning structure Int consisting of a
    > single integer or a bare integer, by value. Both can be and in fact are
    > placed by optimizing compilers to registers. C++ Standard does say one
    > is an rvalue pointing to an object and does not say it about the other;
    > this is clearly a free choice of the Standard authors, not a logical
    > consequence to anything as far as I can see and I would like to know the
    > reason for this choice.
    >
    >>
    >> then the functions would become more similar and we could discuss further
    >> what is allowed and why.
    >>
    >> Cheers
    >> Paavo
    >>

    >
    > TIA
    > -Pavel
    Leo \Equinox\ Gaspard, Jul 3, 2011
    #9
  10. Pavel

    Pavel Guest

    Re: lvalue required as increment operand -- why does the Standardrequires this for fundamental types only?

    Kai-Uwe Bux wrote:
    > Pavel wrote:
    >> SG wrote:

    > ...
    >>> I think Boost provides something similar already and
    >>> it's easy to do it yourself:
    >>>
    >>> 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 and for which ++ would work).

    >
    > Then, what about:
    >
    > template< typename Iter>
    > Iter next ( Iter iter ) {
    > ++ iter;
    > return ( iter );
    > }

    Thanks, that would work. In my actual code, I put up with the temporary
    variable. because adding a new function for this purpose is not enough bang for
    the buck (the bang being not having to add the temporary and the buck being the
    readers of my code having to learn a new function). When it is the part of the
    Standard it probably will be better to use that new next().

    I just thought -- why this restriction is in the Standard? Mainly I am concerned
    that my own iterators and such implemented as classes could be sub-optimal to
    fundamental-type implementations? That's why I was asking for the reason..

    -Pavel

    >
    >
    > Best,
    >
    > Kai-Uwe Bux
    Pavel, Jul 3, 2011
    #10
  11. Pavel

    Pavel Guest

    Re: lvalue required as increment operand -- why does the Standardrequires this for fundamental types only?

    Leo "Equinox" Gaspard wrote:
    > Le 03/07/2011 21:12, Pavel a écrit :
    >> SG wrote:
    >>> On 3 Jul., 11:52, Paavo Helde<> wrote:
    >>>> Pavel wrote:
    >>>>> SG wrote:
    >>>>>> On 2 Jul., 19:30, Pavel wrote:
    >>>>>>> What is the rationale for this lvalue requirement if there is one?
    >>>>>> There is abolutely no reason [for C++] to support prefix ++ on things
    >>>>>> that don't refer to any object.
    >>>>> Thanks, I knew that already. This was not not my question. The
    >>>>> question was about the specific rationale for this decision of the
    >>>>> Standard's authors.
    >>>>
    >>>> You are missing the point.
    >>>
    >>> I have the same feeling. Maybe I left out some detail that is obvious
    >>> to most but not Pavel.
    >>>
    >>>> Supporting ++ on non-objects is logically
    >>>> infeasible, [...]
    >>>
    >>> ...because ++ means "increment that thing and return the new value"
    >>> and you don't want 5 to be 6. ;-)

    >> I do not think my code implies any such semantics. My f1() returns int
    >> by value. So it says "return a copy of this thing and then increment it".
    >>
    >> But maybe I simply didn't get the
    >>> question.
    >>>
    >>> As for genericity: You may implement your own iterator's prefix ++ via
    >>> a member function. But incrementing rvalue iterators is still not part
    >>> of the iterator concept! Otherwise, raw pointers wouldn't be
    >>> iterators. If you want to code generically you better limit yourself
    >>> to the concepts' interfaces.
    >>>
    >>> The standard library of the upcoming C++ ISO standard will provide two
    >>> helper functions: prev and next after including<iterator>. Then you
    >>> can write things like
    >>>
    >>> auto second = next(container.begin());
    >>>
    >>> if you want to. I think Boost provides something similar already and
    >>> it's easy to do it yourself:
    >>>
    >>> 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 and for which ++ would work).
    >>

    >
    > AFAIK it is not the case.
    > advance(N, it) will internally call ++ N times if the operator isn't a
    > random access one. So advance(1, it) should be as efficient as ++it,
    > except maybe a function call, if it ever was not inlined.

    Thanks Leo,

    To do something N times, compiler have to do at least one branch which is not
    necessary for doing that same thing exactly 1 time. Unless advance()
    implementation is at the same translation unit (which may not be the case for
    map iterators etc) compiler cannot optimize out that branch.

    My question is more about the reason for the distinction. Many subtle "gotchas"
    or seeming weirdnesses in the Standard were introduced to keep particular
    optimization options open (whether all of them were in fact useful is another
    question). I am just curious if I am missing anything here. One of the declared
    and more or less consistently pursued goals of C++ was to ensure uniform syntax
    for operations on the objects of fundamental (language's) and class (user's)
    types. The language walked great lengths to fulfill this promise (including the
    whole operator overloading business that I personally disapprove of). Thus I
    suspect there was/is a reason for this particular discrepancy in type handling
    and I would like to know what it is (and why it is kept as is in C++0x if it was
    not good enough a reason).

    -Pavel

    >
    > Cheers,
    > Leo
    >
    >>
    >>>
    >>> Cheers!
    >>> SG

    >>
    >> -Pavel

    >
    Pavel, Jul 3, 2011
    #11
  12. Pavel

    Pavel Guest

    Re: lvalue required as increment operand -- why does the Standardrequires this for fundamental types only?

    Leo "Equinox" Gaspard wrote:
    > Le 03/07/2011 20:51, Pavel a écrit :
    >> Paavo Helde wrote:
    >>> Pavel<> wrote in
    >>> news:4e0f790a$0$21283$c3e8da3$:
    >>>
    >>>> SG wrote:
    >>>>> On 2 Jul., 19:30, Pavel wrote:
    >>>>>>
    >>>>>> What is the rationale for this lvalue requirement if there is one?
    >>>>>>
    >>>>>> -----------------
    >>>>>> int f1() { return 5; }
    >>> [...]
    >>>>>> int main(int, char *[]) {
    >>>>>> //int i1 = ++f1(); (void)i1; // this does not compile
    >>> [...]
    >>>>
    >>>> There is abolutely no
    >>>>> reason to support prefix ++ on things that don't refer to any object.
    >>>> Thanks, I knew that already. This was not not my question. The
    >>>> question was about the specific rationale for this decision of the
    >>>> Standard's authors.
    >>>
    >>> You are missing the point. Supporting ++ on non-objects is logically
    >>> infeasible, it's like writing "++5;" in your program. As we all know
    >>> from
    >>> endless threads with Paul, an object is a region of memory, having a
    >>> certain memory address. The ++ operator would presumable update this
    >>> region of memory somehow, and later the changed content could be
    >>> observed
    >>> by using the same address. If there is no memory region, what should be
    >>> updated? Or if you say a content of CPU register could be updated, how
    >>> could you refer to it afterwards to have any usage of the changes?

    >> I think SG knew what I wanted to do.
    >>
    >> say, for --:
    >>
    >> 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 and does not if it is
    >> happen to be a pointer. I hope this answers yours and SC's questions on
    >> how I am to use these.
    >>
    >> If you know how to fix this code to compile for both class-type and
    >> fundamental-type iterators, without any temporary variables, if
    >> possible, I would appreciate your suggestion.

    >
    > typename C::iterator lastElemIter = c.end(); --lastElemIter;
    >
    > No temporary variables are created, as the compiler is likely to
    > optimize the return type of the function. Indeed, I believe that for
    > class types the second one is even more efficient, as it could use only
    > move-constructor, whereas yours implies a move and a copy constructor.
    >
    > However, I believe the compiler would optimize all of it so the two
    > expressions would act the same way - except that "mine" would work with
    > any iterator type.

    Thanks, yes, it will. It is just a little nuisance; I just wanted to know the
    reason for the difference.

    When I was talking temporary variable I had the actual case where the iterator
    to the last element was to be returned from a function, e.g.

    ....
    if (<cond>)
    return --c.end();
    ....

    as opposed to

    if (<cond>) {
    typename C::iterator i = c.end();
    return --i; // i is a temporary here
    }

    sorry for the confusion.

    >
    > And std::prev(it) (or boost::prior(it)) would also do as you want.

    boost::prior() would help (because it is an overload). Unfortunately, I can't
    use boost in many projects.

    std::prev(), as it is now planned will, unfortunately, have a second parameter
    of difference_type type so it will have same performance issues as std::advance().

    Again, my question was not about the particular use case (I just gave it to
    illustrate why the uniform spec could be useful), but about the reason for the
    discrimination between the fundamental and class types in this regard.

    -Pavel


    >
    > Cheers,
    > Leo
    >
    >>
    >> This
    >>> would require some other language, having different rules. I think in
    >>> some languages one can even change the value of numeric literals ;-)
    >>>
    >>> Now if you changed f1 to read e.g.
    >>>
    >>> int& f1() { return 5; }

    >> I hope you see now it is not relevant to my question. I do not see any
    >> conceptual difference between returning structure Int consisting of a
    >> single integer or a bare integer, by value. Both can be and in fact are
    >> placed by optimizing compilers to registers. C++ Standard does say one
    >> is an rvalue pointing to an object and does not say it about the other;
    >> this is clearly a free choice of the Standard authors, not a logical
    >> consequence to anything as far as I can see and I would like to know the
    >> reason for this choice.
    >>
    >>>
    >>> then the functions would become more similar and we could discuss
    >>> further
    >>> what is allowed and why.
    >>>
    >>> Cheers
    >>> Paavo
    >>>

    >>
    >> TIA
    >> -Pavel

    >
    Pavel, Jul 3, 2011
    #12
  13. Pavel

    SG Guest

    Re: lvalue required as increment operand -- why does the Standardrequires 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 and 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
    SG, Jul 4, 2011
    #13
  14. Pavel

    Pavel Guest

    Re: lvalue required as increment operand -- why does the Standardrequires this for fundamental types only?

    SG wrote:
    > 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 and 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

    Yes, I know. This is because ++ is inlined for list::iterator (and then the
    implementation uses the benefit of known const argument). For map::iterator it
    may not be inline (e.g. it is not in g++ STL, via non-inline
    _Rb_tree_increment()). Because a generic algorithm could be applied to both map
    and list in different instantiations, you want to use ++ if this is what you mean.

    Again, it was just an example of why the uniformness could be useful. My real
    question is "what is the reason for not having uniformness; in particular,
    whether using wrapper classes is sub-optimal somehow".

    >
    > Cheers!
    > SG


    -Pavel
    Pavel, Jul 5, 2011
    #14
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Mr. SweatyFinger
    Replies:
    2
    Views:
    1,739
    Smokey Grindel
    Dec 2, 2006
  2. Replies:
    104
    Views:
    10,927
    Jordan Abel
    Oct 28, 2005
  3. Ben Pfaff

    lvalue required as increment operand

    Ben Pfaff, Dec 24, 2007, in forum: C Programming
    Replies:
    9
    Views:
    2,405
    Keith Thompson
    Dec 25, 2007
  4. Leo \Equinox\ Gaspard
    Replies:
    1
    Views:
    525
    Alf P. Steinbach /Usenet
    Jul 3, 2011
  5. Leo \Equinox\ Gaspard
    Replies:
    2
    Views:
    381
    James Lothian
    Jul 3, 2011
Loading...

Share This Page