class A{
public:
virtual ~A() {};
};
class B : public A{ };
int main(){
A&& p = B();
dynamic_cast<B&&>(std::move(p));
}
Throws the error (g++ 5.2.0):
error: conversion to non-const reference type 'std::remove_reference<A&>::type& {aka class A&}' from rvalue of type 'A' [-fpermissive]
It attempts to cast std::move(p)
to type A&
, but I cannot figure out why. I would've thought it necessary to cast p
as an rvalue before converting to an rvalue reference, but if I remove std::move
it compiles fine. From cppreference:
dynamic_cast < new_type > ( expression )
Similar to other cast expressions, the result is:
an lvalue if new_type is an lvalue reference type (expression must be an lvalue)
an xvalue if new_type is an rvalue reference type (expression may be lvalue or rvalue)
Even 5.2.7 of N3337:
dynamic_cast<T>(v)
If T is a pointer type, v shall be a prvalue of a pointer to complete class type, and the result is a prvalue of type T. If T is an lvalue reference type, v shall be an lvalue of a complete class type, and the result is an lvalue of the type referred to by T. If T is an rvalue reference type, v shall be an expression having a complete class type, and the result is an xvalue of the type referred to by T.
The only requirement there being that I use a complete class type, which std::move(p)
is, isn't it?
An lvalue reference can bind to an lvalue, but not to an rvalue.
To answer the titular question, "rvalue reference" is a kind of type, while "xvalue" is a kind of expression. They are not. Rvalue references are types, types are not expressions and so cannot be "considered lvalue".
Consider this simple hierarchy: class Base { public: virtual ~Base() { } }; class Derived : public Base { }; Trying to downcast Base* p to Derived* is possible using dynamic_cast<Derived*>(p) . I used to think dynamic_cast works by comparing the vtable pointer in p to the one in a Derived object.
Returning a value from a function will turn that value into an rvalue. Once you call return on an object, the name of the object does not exist anymore (it goes out of scope), so it becomes an rvalue. Similarly, calling a function will give back an rvalue. The return value of a function has no name.
Your code is, of course, fine:
If
T
is an rvalue reference type,v
shall be an expression having a complete class type, and the result is an xvalue of the type referred to byT
.
Presumably, dynamic_cast
wasn't updated properly when rvalue references were introduced, and still enforces the pre-C++11 rule that rvalues shall only be bound to const
lvalue references (note that it doesn't even work when altering the target type to B const&&
, despite that being implied by the error message!).
Filed as #69390.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With