Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dynamic_cast and rvalue reference

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?

like image 726
SergeantPenguin Avatar asked Jan 20 '16 13:01

SergeantPenguin


People also ask

Can rvalue references bind to Lvalues?

An lvalue reference can bind to an lvalue, but not to an rvalue.

Is an rvalue reference an Xvalue?

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".

How Dynamic_cast is implemented in compiler?

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.

Can you return an rvalue?

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.


1 Answers

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 by T.

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.

like image 76
Columbo Avatar answered Sep 20 '22 08:09

Columbo