Reputation: 6679
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:
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.
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.
My questions are
Thanks.
Upvotes: 3
Views: 232
Reputation: 42554
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;
};
Upvotes: 2