[C++0x] Is these 2 legal?

Discussion in 'C++' started by Michael Tsang, Mar 4, 2010.

  1. Example 1:

    int main() {
    int x = 5;
    int &&y = x;
    }

    Example 2:

    int &&move(int &&x) {
    return x;
    }

    int main() {
    int x = 5;
    int &&y = move(x);
    }
     
    Michael Tsang, Mar 4, 2010
    #1
    1. Advertising

  2. Re: Is these 2 legal?

    On 4 mar, 10:21, Michael Tsang <> wrote:
    > Example 1:
    >
    > int main() {
    >   int x = 5;
    >   int &&y = x;
    > }


    Yes.

    >
    > Example 2:
    >
    > int &&move(int &&x) {
    >   return x;
    > }
    >
    > int main() {
    >   int x = 5;
    >   int &&y = move(x);
    > }


    Yes.

    --
    Michael
     
    Michael Doubez, Mar 4, 2010
    #2
    1. Advertising

  3. Michael Tsang

    SG Guest

    Re: Is these 2 legal?

    On 4 Mrz., 10:21, Michael Tsang <> wrote:
    > [subject: Is this legal?]


    There is a difference between the old rvalue references and the new
    ones. GCC and MSVC still implement the old behaviour. But rvalue
    references cannot be initialized with lvalue expressions anymore
    according to the new rules.

    Check out:
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2812.html
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2844.html

    I'm applying the new rules in this post.

    > Example 1:
    > int main() {
    >   int x = 5;
    >   int &&y = x;
    > }


    No. It won't comile because x is an lvalue expression.

    > Example 2:
    >
    > int &&move(int &&x) {
    >   return x;
    > }


    No. It won't compile because x is a *named* rvalue reference which
    makes it an lvalue expression. Basically, names (that refer to
    objects) and lvalue references are lvalue expressions. Anything else
    is an rvalue expression. Try this:

    int&& move(int& x) {
    return static_cast<int&&>(x);
    }

    You can cast away "lvalue-ness" with a static cast. std::move is a
    shortcut syntax for a static_cast.

    > int main() {
    >   int x = 5;
    >   int &&y = move(x);
    > }


    This is OK. move returns an unnamed rvalue reference. So, it neither
    has a name, nor is an lvalue reference. This makes it an rvalue
    expression and you can initialize the rvalue reference y with this
    rvalue expression.

    Cheers,
    SG
     
    SG, Mar 4, 2010
    #3
  4. Re: Is these 2 legal?

    On 4 mar, 12:27, SG <> wrote:
    > On 4 Mrz., 10:21, Michael Tsang <> wrote:
    >
    > > [subject: Is this legal?]

    >
    > There is a difference between the old rvalue references and the new
    > ones. GCC and MSVC still implement the old behaviour. But rvalue
    > references cannot be initialized with lvalue expressions anymore
    > according to the new rules.
    >
    > Check out:http://www.open-std.org/jtc1/sc22/w...rg/jtc1/sc22/wg21/docs/papers/2009/n2844.html
    >
    > I'm applying the new rules in this post.
    >
    > > Example 1:
    > >    int main() {
    > >       int x = 5;
    > >       int &&y = x;
    > >    }

    >
    > No. It won't comile because x is an lvalue expression.


    From §5/6 of n3035, AFAIS y will decay to the semantic equivalent of a
    lvalue:
    <quote>
    [ Example:
    struct A { };
    A&& operator+(A, A);
    A&& f();
    A a;
    A&& ar = a;
    The expressions f() and a + a are rvalues of type A. The expression ar
    is an lvalue of type A. —end
    example ]
    </quote>

    > > Example 2:

    >
    > >    int &&move(int &&x) {
    > >       return x;
    > >    }

    >
    > No. It won't compile because x is a *named* rvalue reference which
    > makes it an lvalue expression. Basically, names (that refer to
    > objects) and lvalue references are lvalue expressions. Anything else
    > is an rvalue expression. Try this:
    >
    >    int&& move(int& x) {
    >       return static_cast<int&&>(x);
    >    }
    >
    > You can cast away "lvalue-ness" with a static cast. std::move is a
    > shortcut syntax for a static_cast.



    The generic move is:
    template <class T>
    typename remove_reference<T>::type&&
    move(T&& a)
    {
    return a;
    }

    Replacing T by int (and remove_reference<int>::type ), you get the
    same implementation as the OP.

    >
    > > int main() {
    > >   int x = 5;
    > >   int &&y = move(x);
    > > }

    >
    > This is OK. move returns an unnamed rvalue reference. So, it neither
    > has a name, nor is an lvalue reference. This makes it an rvalue
    > expression and you can initialize the rvalue reference y with this
    > rvalue expression.


    Either I am confused or you are working with an earlier rvalue-
    reference proposal.

    --
    Michael
     
    Michael Doubez, Mar 4, 2010
    #4
  5. Michael Tsang

    SG Guest

    Re: Is these 2 legal?

    On 4 Mrz., 13:32, Michael Doubez <> wrote:
    > On 4 mar, 12:27, SG <> wrote:
    > > On 4 Mrz., 10:21, Michael Tsang <> wrote:

    >
    > > > [subject: Is this legal?]

    >
    > > [...] Check out:
    > > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2812.html
    > > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2844.html

    >
    > > I'm applying the new rules in this post.

    >
    > > > Example 1:
    > > >    int main() {
    > > >       int x = 5;
    > > >       int &&y = x;
    > > >    }

    >
    > > No. It won't comile because x is an lvalue expression.

    >
    > From §5/6 of n3035, AFAIS y will decay to the semantic equivalent
    > of a lvalue:


    Yes, y will behave like any other lvalue except that decltype(y) will
    still be an rvalue reference. That doesn't change the fact that rvalue
    references cannot be initialized with lvalue expressions. See
    §8.5.3/5, the first top-level bullet point covers lvalue references
    that are initialized with lvalue expressions. The second bullet point
    covers the remaining cases. It does not allow initializing rvalue
    references with lvalue expressions anymore:

    " - Otherwise, the reference shall be an lvalue reference to a
    non-volatile const type (i.e., cv1 shall be const), or the
    reference shall be an rvalue reference and the initializer
    expression shall be an rvalue. [...] "

    Note the second half of the sentance and the last "and".

    > <quote>
    > [ Example:
    > struct A { };
    > A&& operator+(A, A);
    > A&& f();
    > A a;
    > A&& ar = a;
    > The expressions f() and a + a are rvalues of type A. The expression ar
    > is an lvalue of type A. —end example ]
    > </quote>


    The example's last line of code is an oversight. See CWG issue #858:
    http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#858

    > > > Example 2:

    >
    > > >    int &&move(int &&x) {
    > > >       return x;
    > > >    }

    >
    > > No. It won't compile because x is a *named* rvalue reference which
    > > makes it an lvalue expression. Basically, names (that refer to
    > > objects) and lvalue references are lvalue expressions. Anything else
    > > is an rvalue expression. Try this:

    >
    > >    int&& move(int& x) {
    > >       return static_cast<int&&>(x);
    > >    }

    >
    > > You can cast away "lvalue-ness" with a static cast. std::move is a
    > > shortcut syntax for a static_cast.

    >
    > The generic move is:
    > template <class T>
    > typename remove_reference<T>::type&&
    > move(T&& a)
    > {
    >     return a;
    > }
    >
    > Replacing T by int (and remove_reference<int>::type ), you get the
    > same implementation as the OP.


    No, it's not. You forgot about the template argument deduction and
    reference collapsing rules. Depending on the kind of argument, the
    reference 'a' will either be an lvalue- or an rvalue reference.
    Examples:

    void g() {
    int i = 24;
    move(i+0); // T=int --> T&& = int&& (rvalue reference)
    move(i); // T=int& --> T&& = int& (lvalue reference)
    }

    In the 2nd case, T will be deduced to be an lvalue reference. Due to
    reference collapsing 'a' will be an lvalue reference, too. This is
    what makes "perfect forwarding" possible. The parameter's "value-ness"
    is part of the reference's type. If you want to emulate this for ints
    without templates you'd have to overload two move functions. One
    taking an lvalue reference and one taking an rvalue reference to int.

    > > > int main() {
    > > >   int x = 5;
    > > >   int &&y = move(x);
    > > > }

    >
    > > This is OK. move returns an unnamed rvalue reference. So, it neither
    > > has a name, nor is an lvalue reference. This makes it an rvalue
    > > expression and you can initialize the rvalue reference y with this
    > > rvalue expression.

    >
    > Either I am confused or you are working with an earlier rvalue-
    > reference proposal.


    I think you are confused. You may want to read David Abrahams
    introductions to rvalue references on his new blog ( http://www.cpp-next.com/
    ). He also explains the "new" rules. I don't remember when the
    proposal N2844 was voted into the draft but it has been published
    about a year ago.

    Cheers,
    SG
     
    SG, Mar 4, 2010
    #5
    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. Valentin Tihomirov

    Is this legal?

    Valentin Tihomirov, Oct 21, 2003, in forum: VHDL
    Replies:
    20
    Views:
    1,258
    Jan Decaluwe
    Oct 29, 2003
  2. Divyang M
    Replies:
    9
    Views:
    639
    Divyang M
    May 18, 2005
  3. Divyang M
    Replies:
    1
    Views:
    574
    Jerzy Gbur
    May 15, 2005
  4. OccasionalFlyer

    Can Either of These be Legal HTML?

    OccasionalFlyer, Jul 2, 2008, in forum: HTML
    Replies:
    21
    Views:
    913
  5. James
    Replies:
    2
    Views:
    296
    James
    Nov 26, 2009
Loading...

Share This Page