How to interpret declval<_Dest>() = declval<_Src>() in is_assignable

c++, c++11

Solution

`std::declval` is actually specified to be (C++11 §20.2.4 [declval] p1):

template <class T>
typename add_rvalue_reference<T>::type declval() noexcept;

The result of the reference collapsing rules (§8.3.2 [dcl.ref] p6) is that `declval` returns an lvalue reference when `T` is an lvalue reference type, and an rvalue reference otherwise. So yes, your interpretation is correct.

If your compiler thinks that `double&&` is assignable from any type, then it has a bug. §5.17 [expr.ass] p1 states:

The assignment operator (`=`) and the compound assignment operators all group right-to-left. All require a modifiable lvalue as their left operand and return an lvalue referring to the left operand.

[emphasis mine].

Many programmers choose to emulate this behavior - assingment only to lvalues - with their own types by declaring the assignment operators with an lvalue reference qualifier:

class foo {
  foo& operator = (const foo&) & = default;
  foo& operator = (foo&&) & = default;
};

Problem

I am trying to figure out how to interpret declval<_Dest>() = declval<_Src>() in the implementation of is_assignable. declval turns a type into a reference. Given that, I translate the expression into one of the following four possibilities: - _Dest&& = _Src&& - _Dest&& = _Src& - _Dest& = _Src&& - _Dest& = _Src& I then created two helper functions. ``` template <typename T> T rvalue(); template <typename T> T& lvalue(); ``` My understanding is the four expressions can be realized by using the template functions. - _Dest&& = _Src&& -----> rvalue<_Dest>() = rvalue<_Src>() Same goes for the other three. Then I simulated decltype(declval<_Dest>() = declval<_Src>(), ..) by compiling the templated function version of each of the possibilities for three pairs of concrete types. - _Dest=int, _Src=int. Compiler accepts #3 and #4. is_assignable returned true for #3 and #4. They agreed. - _Dest=int, _Src=double. Same result as - _Dest=double, _Src=int. For this one, the compiler and is_assignable didn't agree. Compiler again does not like assigning to rvalues. However, is_assignable returns true for all four possibilities. My questions are - Did I interpret declval<_Dest>() = declval<_Src>() correctly? In order words, does this really translate into the four possibilities. If yes, can each one be mapped to a templated function expression? - Why the compiler and is_assignable disagree on the _Dest=double, _Src=int case? Thanks.

Original source