Reputation: 12907
I'm currently trying to implement a really small nested exception mechanism in my code, as std::nested_exception
s 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
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
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