Let's say m
is a non-static data member of non-reference type (T
). According to cppreference, std::move(a).m
is a prvalue until c++11. I guess it should be an xvalue after c++11. Please correct me if I'm wrong.
But the decltype(std::move(a).m)
is still T
(not T&&
) in c++14 (visual studio, clang, gcc), which suggest std::move(a).m
is still a prvalue. So is std::move(a).m
an xvalue or a prvalue?
std::move(a).m
is an xvalue.The new wordings make that much clearer, in [basic.lval]:
By those definitions,
std::move(a).m
is an xvalue and not a prvalue as it denotes an object.The way I find best to think about this is that glvalues have identity and rvalues are safe to move from - where lvalues have identity and are not safe to move from, xvalues have identity and are safe to move from, and prvalues do not have identity and are safe to move from. This taxonomy makes these kinds of questions easier to reason about.
Additionally there is a note in [expr], which is more specific:
std::move(a)
is a cast to rvalue reference, so is an xvalue.std::move(a).m
is a class member access of an xvalue, so is an xvalue.As for
decltype(std::move(a).m)
. Note that the word itself comes from declared type. The rules for whatdecltype(e)
means are complicated, from [dcl.type.simple]:In this case, we have a class member access, so you just get the type of
m
- which isM
and notM&&
. On some level this makes sense, you're asking for the declared type ofm
and you got the declared type ofm
.If you want to categorize it properly, you can force that bullet to be ignored with an extra set of parentheses (obviously):
decltype((std::move(a).m))
would give youM&&
.