JBL
JBL

Reputation: 12907

Casting a rvalue reference parameter to a rvalue reference?

I'm currently trying to implement a really small nested exception mechanism in my code, as std::nested_exceptions aren't available for all the compilers I must compile my code with.

I came across the following useful nesting wrapper in the gcc implementation source code:

template<typename _Except>
struct _Nested_exception : public _Except, public nested_exception
{
    explicit _Nested_exception(_Except&& __ex)
    : _Except(static_cast<_Except&&>(__ex))
    { }
};

which allows to combine an exception that has been thrown with the nested_exception class in throw_with_nested so that one can dynamic_cast to test whether the exception we've caught is actually a nested exception or not later on.

What I don't understand is the static_cast here. I think I'm missing something about move-semantics, is it really needed?

Upvotes: 1

Views: 373

Answers (2)

jepio
jepio

Reputation: 2281

Move semantics means that we know that this constructor has been called with a parameter that is a temporary (or to-be-moved-from object). We see this in the type of __ex which is _Except&&. However if we were to use __ex within this constructor it would be treated as an lvalue - it clearly has a name and we can take it's address.

If you want to pass __ex to any further functions/constructors, it's rvalue-ness needs to be restored. The normal way to do so is by calling std::move(__ex) which will reapply && to the type of __ex. This is really just the same static_cast that you see above.

Upvotes: 2

Jake M
Jake M

Reputation: 56

Although __ex is an _Except&&, once you enter this scope __ex is an lvalue - it's a local variable. To enforce the use of the move constructor inside of _Except they do _Except(static_cast<_Except&&>(__ex)) to force __ex to become an rvalue (it's probably actually an xvalue).

Upvotes: 2

Related Questions