16
votes
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?

2
Clang has no problems with your codeCubbi
Confirmed with gcc 5.3. Works without the std::move call, though. ;)erip
...as you noted in your question. I should read questions more thoroughly.erip

2 Answers

7
votes

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.

3
votes

This seems to work instead:

B&& b = std::move(dynamic_cast<B&>(p));

Can't tell you why yours is incorrect.