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
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; }
// ^
};