Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is 'declval' specified in terms of 'add_rvalue_reference<T>::type' and not 'T&&'?

Tags:

§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 typedef type shall name T&&; otherwise, type shall name T. [ Note: This rule reflects the semantics of reference collapsing (8.3.2). For example, when a type T names a type T1&, the type add_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?

like image 678
Xeo Avatar asked Jan 21 '12 17:01

Xeo


2 Answers

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.

like image 188
Pubby Avatar answered Oct 20 '22 14:10

Pubby


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.

like image 31
Howard Hinnant Avatar answered Oct 20 '22 15:10

Howard Hinnant