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.