Giving an rvalue ref to a function taking an rvalue ref

Discussion in 'C++' started by Juha Nieminen, Aug 20, 2012.

  1. Suppose you have a function that takes an rvalue reference as parameter,
    and from within it you want to call another function that likewise takes
    one, but there's also a version of that function that takes a regular
    reference. (This is most often the case with copy/move constructors and
    assignment operators.)

    In order to call the version taking the rvalue reference, you have to
    explicitly re-cast the parameter with std::move (or static_cast<type&&>()).

    For example, if you were writing a move constructor in a derived class,
    you would need to write it like:

    MyClass(MyClass&& rhs): BaseClass(std::move(rhs)) {}

    Or, if you want:

    MyClass(MyClass&& rhs): BaseClass(static_cast<MyClass&&>(rhs)) {}

    Without the explicit cast, the normal copy constructor of the base class
    would be called instead. (The same is true if you were implementing the
    move assignment operator.)

    But why is the explicit re-casting necessary?
     
    Juha Nieminen, Aug 20, 2012
    #1
    1. Advertising

  2. Juha Nieminen

    Luca Risolia Guest

    On 20/08/2012 12:29, Juha Nieminen wrote:
    > Suppose you have a function that takes an rvalue reference as parameter,
    > and from within it you want to call another function that likewise takes
    > one, but there's also a version of that function that takes a regular
    > reference. (This is most often the case with copy/move constructors and
    > assignment operators.)
    >
    > In order to call the version taking the rvalue reference, you have to
    > explicitly re-cast the parameter with std::move (or static_cast<type&&>()).
    >
    > For example, if you were writing a move constructor in a derived class,
    > you would need to write it like:
    >
    > MyClass(MyClass&& rhs): BaseClass(std::move(rhs)) {}
    >
    > Or, if you want:
    >
    > MyClass(MyClass&& rhs): BaseClass(static_cast<MyClass&&>(rhs)) {}
    >
    > Without the explicit cast, the normal copy constructor of the base class
    > would be called instead. (The same is true if you were implementing the
    > move assignment operator.)
    >
    > But why is the explicit re-casting necessary?


    Because the rvalue reference rhs is, in fact, a lvalue inside the
    MyClass constructor. It is an object with a name, you can get its
    address, and will be alive for the whole duration of the constructor, so
    you need an explicit cast to apply move semantics again.
     
    Luca Risolia, Aug 20, 2012
    #2
    1. Advertising

  3. Juha Nieminen

    SG Guest

    On Aug 20, 12:29 pm, Juha Nieminen wrote:
    > Suppose you have a function that takes an rvalue reference as parameter,
    > and from within it you want to call another function that likewise takes
    > one, but there's also a version of that function that takes a regular
    > reference. (This is most often the case with copy/move constructors and
    > assignment operators.)
    >
    > In order to call the version taking the rvalue reference, you have to
    > explicitly re-cast the parameter with std::move (or static_cast<type&&>()).
    >
    > For example, if you were writing a move constructor in a derived class,
    > you would need to write it like:
    >
    >     MyClass(MyClass&& rhs): BaseClass(std::move(rhs)) {}
    >
    > Or, if you want:
    >
    >     MyClass(MyClass&& rhs): BaseClass(static_cast<MyClass&&>(rhs)) {}
    >
    > Without the explicit cast, the normal copy constructor of the base class
    > would be called instead. (The same is true if you were implementing the
    > move assignment operator.)
    >
    > But why is the explicit re-casting necessary?


    It is necessary because rhs is an lvalue expression. Its declared type
    only affects how you can initialize it. That's about it. You can use
    this name to refer to the same object multiple times. That's the
    quality of lvalues! If you have a way of accessing the same object
    multiple times by a simple name this name ought to be an lvalue
    expression because otherwise you would probably get accidental and
    undesired mutations. It's much better and safer to be explicit about
    when you lose interest in a named object (which means the use of
    std::move or std::forward).

    Keep in mind that the value category is not a quality of an object,
    but a quality of an expression. Once you initialize a _named_
    reference to refer to some object, this name is an lvalue expression
    and it won't matter what its declared type is -- for safety reasons.

    Cheers!
    SG
     
    SG, Aug 20, 2012
    #3
  4. Juha Nieminen

    Guest

    On Monday, August 20, 2012 5:29:58 AM UTC-5, Juha Nieminen wrote:
    > Suppose you have a function that takes an rvalue reference as parameter,
    >
    > and from within it you want to call another function that likewise takes
    >
    > one, but there's also a version of that function that takes a regular
    >
    > reference. (This is most often the case with copy/move constructors and
    >
    > assignment operators.)
    >
    >
    >
    > In order to call the version taking the rvalue reference, you have to
    >
    > explicitly re-cast the parameter with std::move (or static_cast<type&&>()).
    >
    >
    >
    > For example, if you were writing a move constructor in a derived class,
    >
    > you would need to write it like:
    >
    >
    >
    > MyClass(MyClass&& rhs): BaseClass(std::move(rhs)) {}
    >
    >
    >
    > Or, if you want:
    >
    >
    >
    > MyClass(MyClass&& rhs): BaseClass(static_cast<MyClass&&>(rhs)) {}
    >
    >
    >
    > Without the explicit cast, the normal copy constructor of the base class
    >
    > would be called instead. (The same is true if you were implementing the
    >
    > move assignment operator.)
    >
    >
    >
    > But why is the explicit re-casting necessary?


    The thing is that there's a difference between "rvalue references" and just"rvalues". Rvalue references I guess are just named rvalue references (i.e.. variables), whereas rvalues are basically things similar to temporary objects (like by-value return values). And rvalue references are actually lvalues (yes, L). The rationale for that obviously is that a named rvalue reference is no longer a temporary object that's about to be destroyed (even though it was initialized with one), so it shouldn't be (implicitly) assignable to other rvalue references.
     
    , Aug 20, 2012
    #4
  5. Juha Nieminen

    SG Guest

    On 22 Aug., 17:07, Edek Pienkowski wrote:
    > [...]
    > point to any rationale behind that. The point is that the rules could
    > have been set differently and if they are as they are there must be
    > some reasoning behind it - not just how the rules are formulated.


    As I said, "it makes sense". Names of objects are lvalues. The name of
    an
    rvalue reference is still a name you can use to refer to the same
    object
    multiple times. That's an lvalue quality. You DON'T want a name for an
    object to be an rvalue expression -- even if it's the name of an
    rvalue
    reference -- because this would lead to accidental moves. So, for
    safety
    reasons one has to be explicit about when one loses interest in a
    NAMED
    object.

    HTH,
    SG
     
    SG, Aug 22, 2012
    #5
  6. Juha Nieminen

    Luca Risolia Guest

    On 22/08/2012 17:07, Edek Pienkowski wrote:
    > Dnia Mon, 20 Aug 2012 13:38:28 +0200, Luca Risolia napisal:
    >
    >> On 20/08/2012 12:29, Juha Nieminen wrote:
    >>> Suppose you have a function that takes an rvalue reference as parameter,
    >>> and from within it you want to call another function that likewise takes
    >>> one, but there's also a version of that function that takes a regular
    >>> reference. (This is most often the case with copy/move constructors and
    >>> assignment operators.)
    >>>
    >>> In order to call the version taking the rvalue reference, you have to
    >>> explicitly re-cast the parameter with std::move (or static_cast<type&&>()).
    >>>
    >>> For example, if you were writing a move constructor in a derived class,
    >>> you would need to write it like:
    >>>
    >>> MyClass(MyClass&& rhs): BaseClass(std::move(rhs)) {}
    >>>
    >>> Or, if you want:
    >>>
    >>> MyClass(MyClass&& rhs): BaseClass(static_cast<MyClass&&>(rhs)) {}
    >>>
    >>> Without the explicit cast, the normal copy constructor of the base class
    >>> would be called instead. (The same is true if you were implementing the
    >>> move assignment operator.)
    >>>
    >>> But why is the explicit re-casting necessary?

    >>
    >> Because the rvalue reference rhs is, in fact, a lvalue inside the
    >> MyClass constructor. It is an object with a name, you can get its
    >> address, and will be alive for the whole duration of the constructor, so
    >> you need an explicit cast to apply move semantics again.

    >
    > The question was not "what is necessary" but "why". I actually often
    > wondered why the explicit re-casting is necessary, and your answer is no
    > answer, because it only explains the semantic rules and does not
    > point to any rationale behind that. The point is that the rules could
    > have been set differently and if they are as they are there must be
    > some reasoning behind it - not just how the rules are formulated.
    >
    > You're not the only person giving this explanation when asked "why"
    > to tell the truth. Who is the magnificent author of this repeated
    > idiom?


    The key thing to understand was that rhs is a lvalue expression in the
    constructor, despite its declaration. That is what might be really
    confusing for many people in my opinion. And once you know that, think
    about the consequences of a - possible - implicit cast. They would be
    obvious, if you knew the C++ basics better.
     
    Luca Risolia, Aug 22, 2012
    #6
  7. On Wed, 22 Aug 2012 16:30:11 +0000 (UTC), Edek Pienkowski
    <> wrote:
    > Dnia Wed, 22 Aug 2012 18:10:38 +0200, Luca Risolia napisal:



    > > On 22/08/2012 17:07, Edek Pienkowski wrote:
    > >> Dnia Mon, 20 Aug 2012 13:38:28 +0200, Luca Risolia napisal:
    > >>
    > >>> On 20/08/2012 12:29, Juha Nieminen wrote:
    > >>>> Suppose you have a function that takes an rvalue reference as

    parameter,
    > >>>> and from within it you want to call another function that

    likewise takes
    > >>>> one, but there's also a version of that function that takes a

    regular
    > >>>> reference. (This is most often the case with copy/move

    constructors and
    > >>>> assignment operators.)
    > >>>>
    > >>>> In order to call the version taking the rvalue reference, you

    have to
    > >>>> explicitly re-cast the parameter with std::move (or

    static_cast<type&&>()).
    > >>>>
    > >>>> For example, if you were writing a move constructor in a

    derived class,
    > >>>> you would need to write it like:
    > >>>>
    > >>>> MyClass(MyClass&& rhs): BaseClass(std::move(rhs)) {}
    > >>>>
    > >>>> Or, if you want:
    > >>>>
    > >>>> MyClass(MyClass&& rhs):

    BaseClass(static_cast<MyClass&&>(rhs)) {}
    > >>>>
    > >>>> Without the explicit cast, the normal copy constructor of the

    base class
    > >>>> would be called instead. (The same is true if you were

    implementing the
    > >>>> move assignment operator.)
    > >>>>
    > >>>> But why is the explicit re-casting necessary?
    > >>>
    > >>> Because the rvalue reference rhs is, in fact, a lvalue inside

    the
    > >>> MyClass constructor. It is an object with a name, you can get

    its
    > >>> address, and will be alive for the whole duration of the

    constructor, so
    > >>> you need an explicit cast to apply move semantics again.
    > >>
    > >> The question was not "what is necessary" but "why". I actually

    often
    > >> wondered why the explicit re-casting is necessary, and your

    answer is no
    > >> answer, because it only explains the semantic rules and does not
    > >> point to any rationale behind that. The point is that the rules

    could
    > >> have been set differently and if they are as they are there must

    be
    > >> some reasoning behind it - not just how the rules are formulated.
    > >>
    > >> You're not the only person giving this explanation when asked

    "why"
    > >> to tell the truth. Who is the magnificent author of this repeated
    > >> idiom?

    > >
    > > The key thing to understand was that rhs is a lvalue expression

    in the
    > > constructor, despite its declaration. That is what might be

    really
    > > confusing for many people in my opinion. And once you know that,

    think
    > > about the consequences of a - possible - implicit cast. They

    would be
    > > obvious, if you knew the C++ basics better.



    > The rules could have been that it is not a cast - it is declared as
    > rvalue-ref and only the standard says that it is named and as such

    is
    > an lvalue. It could have been that a cast would be necessary in
    > the opposite direction - to get an lvalue from the declared (which
    > means explicit) rvalue-ref. Although I agree the the _ref_ is an
    > lvalue by nature more than an rvalue; my point would be that
    > rvalue-ref is more of an rvalue-_ref_ than an lvalue.



    > I do know C++ and hell lot more than the basics, yet I do not quite
    > follow why rvalue-ref is considered an lvalue (ok, I do
    > know that the standard says that if it is named then it is an
    > lvalue, no need to repeat that in the thread for the fifth time;
    > I do not quite get _why_). What would be the consequences of
    > the opposite choice? For me it would mean less typing, I mean
    > how often do you need to actually pass an rvalue-ref to
    > something taking a reference or a value (cv-qualified)
    > _and at the same time_ the same thing has a signature
    > which takes an rvalue-ref? Any idiomatic example?



    > Edek Pienkowski


    a function taking a rvalue ref may need to do some calculation
    with the value before passing it to another rvalue-ref taking
    function.

    in your scheme this would be written as:

    void foo( bar && rref )
    {
    do_some_calculation( std::lval( rref ) );
    do_more_calculations( std::lval( rref ) );
    move_from_rref( rref );
    }

    as it is now:

    void foo( bar && rref )
    {
    do_some_calculation( rref );
    do_more_calculations( rref );
    move_from_rref( std::move( rref ) );
    }

    In your scheme, you need to ensure that every reference to rref
    before the last
    uses std::lval, whereas as it is currently, you just need to ensure
    that there are
    no references to rref after the call to std::move, which is easier to
    check.
    Furthermore, if you forgot the std::lval in your scheme, then there
    would
    be a runtime error on the next use of rref, whereas as it is
    currently, forgetting
    std::move will still run as intended just not as optimally (assuming
    there is a
    non-rvalue move_from_rref declared).
    Therefore, the rules in the standard, while resulting in more typing
    for the simplest
    case, are safer for other use cases.
     
    Garrett Hartshaw, Aug 23, 2012
    #7
  8. Edek Pienkowski <> wrote:
    > Rvalue-ref is not an rvalue, that is clear. I still do not see why it
    > is implicitly an lvalue and not an rvalue-ref.
    >
    > A good example would help.
    >
    > Edek Pienkowski


    The important point is that you must not confuse the type of an expression
    with its value category.

    Every expression has a
    - value, which has two properties:
    - value category, one of
    - lvalue
    - rvalue
    - type, for example:
    - int
    - int&
    - int&&

    Type and value category are essentially independent of each other.
    However, there are rules, how expressions can _bind_ to types, especially
    reference types:
    - lvalue expressions can only bind to normal references.
    - rvalue expressions can bind to both, normal and rvalue references.

    Tobi
     
    Tobias Müller, Aug 23, 2012
    #8
  9. Juha Nieminen

    SG Guest

    On 22 Aug., 18:47, Edek Pienkowski wrote:
    >
    > Rvalue-ref is not an rvalue, that is clear.


    This is not 100% correct.
    A _named_ rvalue reference is not an rvalue.

    > I still do not see why it
    > is implicitly an lvalue and not an rvalue-ref.


    Because it has a _name_. Having a _name_ allows you to refer to it
    more than once. If you have the chance to refer to an object more than
    once you might expect its value not to change by writing innocent-
    looking code like

    void push_twice(string const& what,
    vector<string>& target1, vector<string>& target2)
    {
    target1.push_back(what);
    target2.push_back(what);
    }

    void push_twice(string && what,
    vector<string>& target1, vector<string>& target2)
    {
    target1.push_back(what);
    target2.push_back(what);
    }

    If a named rvalue reference was an rvalue expression the string would
    have been _implicitly_ moved into target1 even though it has a name
    ("what") and can be referred to multiple times. This would make
    target2
    contain an empty string at the end. To get the indented behaviour one
    would have to write

    void push_twice(string && what,
    vector<string>& target1, vector<string>& target2)
    {
    target1.push_back(constify(what));
    target2.push_back(what);
    }

    where "constify" would return an lvalue ref to const to prevent the
    string from moving into the vector target1. This, however is much more
    error prone than the actual rules. Under the actual rules you'd write

    void push_twice(string && what,
    vector<string>& target1, vector<string>& target2)
    {
    target1.push_back(what);
    target2.push_back(move(what));
    }

    and have the "rvalueness" explicit. There is no good reason to make
    named rvalue references into rvalues implicitly. Having a name is
    something that screams "Lvalue". The rule is simple: All names of
    objects are lvalues. And "name" doesn't have to be an identifier. It
    might be any expression you can use to refer to the same object
    multiple times. That's what lvalues are about. Of course, a named
    rvalue reference is an lvalue, too.

    Don't get confused with the name "rvalue reference". Its name only
    describes that you can only _initialize_ rvalue references to refer to
    objects nobody cares about because either they don't have a handle on
    them or they explicitly declared that they are not interested in them
    (via std::move of std::forward).

    Cheers!
    SG
     
    SG, Aug 23, 2012
    #9
  10. Juha Nieminen

    SG Guest

    On 23 Aug., 11:29, Edek Pienkowski wrote:
    > I won't be a bore and I won't ask again just because you repeated
    > that it is "named" and "error prone" and that it is so.


    The "named" thing is about consistency. Named things ought to be
    lvalues. That's the idea behind lvalues. Lvalues are things you have a
    reusable handle on. Together with your desired rules being error
    prone, it think it's a strong case for the current rules.

    > There are features in C++ which are error prone - such as a
    > reference to a temporary - and they do exist.


    In my opinion, that's not a good enough reason to deliberately
    introduce rules that make C++ more error prone.

    > [...]
    > But I am also one of those people for whom less typing [...]
    > I am simply against tedious typing,
    > and from this point of view this little extra safety is not
    > worth it as much as for instance in the default memory ordering


    That's your opinion. I don't agree with it. It's not only safety but
    consistency w.r.t. named things being lvalues.

    > (which _is_ a tradeoff: safety against performance).
    >
    > In most cases std::move is the only usage of the variable, at least
    > in the standard library implementation. Funny enough, the first two
    > cases I have found which do include multiple usage of the variable
    > actually do use it after std::move, though with care. Here:
    >
    >       template<typename _Tp, typename _Del>
    >         explicit
    >         __shared_count(std::unique_ptr<_Tp, _Del>&& __r)
    >         : _M_pi(_S_create_from_up(std::move(__r)))
    >         { __r.release(); }


    As long as it's clear what _S_create_from_up does (which is a private
    static of the same class and thus part of the implementation which is
    free to do whatever it likes as long as its behaviour matches the
    specification) I'm fine with it.

    You could even get rid of this std::move thing if you made
    _S_create_from_up take an lvalue-ref-to-const. This function simply
    observes __r and doesn't change it. I really don't know what the
    author(s) thought while writing this. I probably would have made
    _S_create_from_up to take a lref-to-const and ditched the std::move
    call. This constructor taking an rref is perfectly fine. This is an
    ownership transfer to __shared_count and the reference unique_ptr is
    "released" of its duties.

    >       template<typename _Tp1, typename _Del>
    >         __shared_ptr(std::unique_ptr<_Tp1, _Del>&& __r)
    >         : _M_ptr(__r.get()), _M_refcount()
    >         {
    >           __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)
    >           _Tp1* __tmp = __r.get();
    >           _M_refcount = __shared_count<_Lp>(std::move(__r));
    >           __enable_shared_from_this_helper(_M_refcount, __tmp, __tmp);
    >         }
    >
    > Where is your safety?


    Where's the read access of __r after its std::move call? And even it
    there was one: As the implementer of unique_ptr and shared_ptr you can
    of course rely on your own implementation's behaviour. This looks
    perfectly fine to me. I don't know what you were getting at with this
    example.

    > Why would I have to type std::move in about 30
    > other cases where std::move(var) is the only usage of var?


    Because it's less error prone and more consistent with named things
    being lvalues. Because it's a good idea to be explicit about when you
    lose interest in the "value" of a named object. ;)

    But I think it's a good idea to explore the possibility (and its
    implications) of automatically treating named rvalue references and
    names of automatic objects ON THEIR LAST USE as rvalues. The problem I
    see here is that determining what use is actually the last one can by
    very tricky. Consider loops, consider conditional branches, etc.

    > Should
    > I get compiler warnings for the above contructs? Could I not
    > get those compiler warning if the standard implicitly did not
    > make (some) rvalue-refs lvalues? The compiler does know how the value
    > is bound so the answer to the last question is easy to find.


    Sorry, I don't follow.

    > > [...] you can only _initialize_ rvalue references to refer to
    > > objects nobody cares about because either they don't have a handle on
    > > them or they explicitly declared that they are not interested in them
    > > (via std::move of std::forward).

    >
    > std::forward is only remotely related to std::move, their main similarity
    > is syntactical - the only link is the case where a single rvalue reference
    > can be both used and forwarded. Who's confused?


    I'm not. std::forward is a kind of conditional move request that
    depends (typically) on a template parameter. After forwarding an x
    using std::forward<X>(x) to some other function or function object you
    won't see many read accesses to x anymore in real code.

    Cheers!
    SG
     
    SG, Aug 24, 2012
    #10
  11. On Wednesday, August 22, 2012 11:07:17 AM UTC-4, Edek Pienkowski wrote:
    > You're not the only person giving this explanation when asked "why"
    > to tell the truth. Who is the magnificent author of this repeated
    > idiom?


    Here is the first mention of it in the C++ committee technical papers:

    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1377.htm#More on A&&

    The section "More on A&&" lays out the rationale for why variables declared with rvalue reference type are treated as lvalues when used in expressions.

    Howard
     
    Howard Hinnant, Aug 25, 2012
    #11
  12. Juha Nieminen

    SG Guest

    On 25 Aug., 21:07, Howard Hinnant wrote:
    > Here is the first mention of it in the C++ committee technical
    > papers:
    > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1377.htm#More on A&&
    > The section "More on A&&" lays out the rationale for why variables
    > declared with rvalue reference type are treated as lvalues when
    > used in expressions.


    That's about the same reasoning (error proneness) with a very similar
    example (two uses of named rrefs) -- just saying.

    Cheers!
    SG
     
    SG, Aug 26, 2012
    #12
  13. Juha Nieminen

    SG Guest

    On 25 Aug., 10:58, Edek Pienkowski wrote:
    > Dnia Fri, 24 Aug 2012 02:20:16 -0700, SG napisal:
    > > Edek Pienkowski wrote:
    > >> In most cases std::move is the only usage of the variable, [...]

    >
    > My point is that it is up the author of any given code to know
    > when one would use a variable after std::move. Just like here:
    > knowing what can be assumed of taking an rvalue reference, futhermore
    > that usage is std::move and not std::forward-ing it later, one can know
    > it is safe. It is only partial safety.


    I would go as far as saying that the code you showed for
    __shared_count is non-idiomatic. The original idea was to overload
    functions (or constructors) using lref-to-const and rref-to-non-const
    parameters where the functions "logically" don't modify their
    arguments. For example operator+ on strings is not "logically"
    supposed to mutate its arguments. The rref overload is just an
    optimization for the case that nobody would care about a mutation.
    Here, we have just a single function that takes an rref for no good
    reason. It could just as well be an lref or even an lref-to-const
    since it doesn't even modify its argument.

    > Two points: often [std::move(named_rref)] is THE ONLY USE.


    Probably.

    > [...]
    > >> std::forward is only remotely related to std::move, their main similarity
    > >> is syntactical - the only link is the case where a single rvalue reference
    > >> can be both used and forwarded. Who's confused?

    >
    > > I'm not. std::forward is a kind of conditional move request that
    > > depends (typically) on a template parameter. After forwarding an x
    > > using std::forward<X>(x) to some other function or function object you
    > > won't see many read accesses to x anymore in real code.

    >
    > It depends on the author(s) of this code. Like in the above examples:
    > we know what that does, we are safe actually using it afterwards.


    As I said, I consider this code not to be idiomatic. It's more like an
    rref abuse.

    > I have little practice, but I think std::forward may not be a move
    > at all in the end.


    I deliberately used the the term "move request" instead of "move".
    Depending on T std::forward<T>(x) might have exactly the same effect
    as std::move(x) and std::move is nothing but a "move request" or more
    like a "I don't care about this variable's value anymore" declaration
    -- at least that's how it should be used.

    "Using it afterwards" may just be an assignment which should be
    perfectly fine. Read accesses are more problematic and should not
    happen in generic code at least.

    Cheers!
    SG
     
    SG, Aug 26, 2012
    #13
  14. Dnia Sat, 25 Aug 2012 12:07:35 -0700, Howard Hinnant napisal:

    > On Wednesday, August 22, 2012 11:07:17 AM UTC-4, Edek Pienkowski wrote:
    >> You're not the only person giving this explanation when asked "why"
    >> to tell the truth. Who is the magnificent author of this repeated
    >> idiom?

    >
    > Here is the first mention of it in the C++ committee technical papers:
    >
    > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1377.htm#More on A&&
    >
    > The section "More on A&&" lays out the rationale for why variables
    > declared with rvalue reference type are treated as lvalues when used in
    > expressions.


    Thanks, that was a good read. I was always curious how std::forward
    without any special compiler treatment manages to forward lvalues _not_
    to rvalue refs even is this choice is available. It is cool.

    Also, I might have been less explicit in critisism - sorry for words.
    Now that I know how arcane this feature is - and without any compiler
    tricks - I will be much more happy while figuring out how to put
    std::move under some keyboard shortcut in my favourite IDE. Oh,
    when I will actually want to std::move something without being
    accused of premature optimisation - needless to say rvalue-ref is most
    people's favourite c++0x feature so that won't be a problem.

    --
    Edek
     
    Edek Pienkowski, Aug 29, 2012
    #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. Kavya
    Replies:
    9
    Views:
    541
    Dik T. Winter
    Oct 28, 2006
  2. sixteenmillion

    The giving that keeps on giving

    sixteenmillion, Nov 19, 2007, in forum: C Programming
    Replies:
    0
    Views:
    455
    sixteenmillion
    Nov 19, 2007
  3. Replies:
    0
    Views:
    363
  4. Replies:
    22
    Views:
    794
    peter koch
    Apr 30, 2008
  5. Jim Cain
    Replies:
    1
    Views:
    229
    Yukihiro Matsumoto
    Jul 18, 2003
Loading...

Share This Page