Is there a reason declval returns add_rvalue_reference instead of add_lvalue_reference

With add_rvalue_reference:

  • declval<Foo>() is of type Foo&&.
  • declval<Foo&>() is of type Foo& (reference collapsing: “Foo& &&” collapses to Foo&).
  • declval<Foo&&>() is of type Foo&& (reference collapsing: “Foo&& &&” collapses to Foo&&).

With add_lvalue_reference:

  • declval<Foo>() would be of type Foo&.
  • declval<Foo&>() would be of type Foo& (reference collapsing: “Foo& &” collapses to Foo&).
  • declval<Foo&&>() would be of type Foo& (!) (reference collapsing: “Foo&& &” collapses to Foo&).

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).

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)