With add_rvalue_reference:
declval<Foo>()is of typeFoo&&.declval<Foo&>()is of typeFoo&(reference collapsing: “Foo& &&” collapses toFoo&).declval<Foo&&>()is of typeFoo&&(reference collapsing: “Foo&& &&” collapses toFoo&&).
With add_lvalue_reference:
declval<Foo>()would be of typeFoo&.declval<Foo&>()would be of typeFoo&(reference collapsing: “Foo& &” collapses toFoo&).declval<Foo&&>()would be of typeFoo&(!) (reference collapsing: “Foo&& &” collapses toFoo&).
that is, you would never get a Foo&&.
Also, the fact that declval<Foo>() is of type Foo&& is fine (you can write Foo&& rr = Foo(); but not Foo& lr = Foo();). And that declval<Foo&&>() would be of type Foo& just feels “wrong”!
Edit: Since you asked for an example:
#include <utility>
using namespace std;
struct A {};
struct B {};
struct C {};
class Foo {
public:
Foo(int) { } // (not default-constructible)
A onLvalue() & { return A{}; }
B onRvalue() && { return B{}; }
C onWhatever() { return C{}; }
};
decltype( declval<Foo& >().onLvalue() ) a;
decltype( declval<Foo&&>().onRvalue() ) b;
decltype( declval<Foo >().onWhatever() ) c;
If declval used add_lvalue_reference you couldn’t use onRvalue() with it (second decltype).