2

So I've been learning about rvalues and rvalue references and have run into some code while experimenting that I can't wrap my head around the errors of.

int&& test1(int& t)
{
    return static_cast<int&&>(t);
}

std::string&& test2(std::string& t)
{
    return static_cast<std::string&&>(t);
}


int main()
{
    int n ;
    std::string s;
    static_cast<int&&>(n) = 9;        //Error: expression must be a modifiable lvalue
    static_cast<std::string&&>(s) = "test";  //Compiles and runs fine
    test1(n) = 4;                     //Error: expression must be a modifiable lvalue
    test2(s) = "hello";               //Compiles and runs fine 
}

I was just wondering what the differences are in how rvalue references of std::strings and ints are handled and why one works and one doesn't.

I'm using Visual Studio 2019 with C++17

songyuanyao
  • 169,198
  • 16
  • 310
  • 405

1 Answers1

2

Because C++ treats class types and build-in types in different ways.

For build-in types, rvalues can't be assgined.

For class types, e.g. std::string, test2(h) = "hello"; is just same as test2(h).operator=("hello");; operator= is the member of std::string, it's not special with other member functions. This is valid, if the member operator= is allowed to be called on an rvalue, and this is true for std::string::operator=. You can even write something like std::string{} = "hello";, i.e. assign to a temporary which will be destroyed soon, which doesn't make much sense indeed.

If you want to constrain the member function of user-defined class can only be called on lvalues, you can specify lvalue ref-qualifier (since C++11), or vice versa. e.g.

struct X {
    X& operator=(const char*) & { return *this; }
    //                        ^
};

LIVE

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • This does make sense to me now, thanks. But I have a follow-up question. When I make a custom class and try to do the same r-value-reference assignment as before, it works, like it does for std::string. Is this because of the implicit move assignment operator that is generated? – Isaac Morton Jul 02 '19 at 01:36
  • @IsaacMorton Answer revised. The implicitly-generated assignment operator doesn't have ref-qualifier specified, the behavior is jsut same as you seen with `std::string`. – songyuanyao Jul 02 '19 at 01:51
  • Thanks for all the help. Especially the ref-qualifier, would never have found that if not for your answer. Quite helpful indeed! – Isaac Morton Jul 02 '19 at 02:00