§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
Tnames an object or function type then the member typedeftypeshall nameT&&; otherwise,typeshall nameT. [ Note: This rule reflects the semantics of reference collapsing (8.3.2). For example, when a typeTnames a typeT1&, the typeadd_rvalue_reference<T>::typeis 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