§20.2.4 [declval]
template <class T>
typename add_rvalue_reference<T>::type declval() noexcept; // as unevaluated operand
Why use add_rvalue_reference
here?
From §20.9.7.2 [meta.trans.ref]
on add_rvalue_reference
:
If
T
names an object or function type then the member typedeftype
shall nameT&&
; otherwise,type
shall nameT
. [ Note: This rule reflects the semantics of reference collapsing (8.3.2). For example, when a typeT
names a typeT1&
, the typeadd_rvalue_reference<T>::type
is not an rvalue reference. —end note ]
Since add_rvalue_reference
is meant to reflect reference collapsing anyways, why not just use T&&
like the following?
template<class T>
T&& declval();
What could go wrong? What exactly are the differences between the two versions?
I don't know if this is the actual reason, but add_rvalue_reference
has different behavior for void
.
add_rvalue_reference<void>::type
is simply void
.
void&&
is an error.
Several definitions depend upon declval
giving reasonable results for cv-qualified void
. An example is is_assignable
:
template <class T, class U>
struct is_assignable;
The expression
declval<T>() = declval<U>()
is well-formed when treated as an unevaluated operand ...
The intent is that "well-formed" refers to the well-formed-ness of the assignment expression, and not whether declval<T>
itself is well-formed. I.e. we want to worry about just one thing at a time.
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