Here is some code in VS2015:
class Elem
{
public:
Elem(int i) : a(i) {}
Elem(Elem && other) = default;
Elem(const Elem & other) = default;
private:
int a;
};
int main()
{
std::vector<Elem> vv;
// case 0
vv.push_back(Elem{ 0 }); // call push_back(Elem &&);
// case 1
Elem e1{ 1 };
vv.push_back(e1); // call push_back(const Elem &);
// case 2
Elem e2{ 2 };
auto & lref = e2;
vv.push_back(lref); // call push_back(const Elem &);
// case 3
Elem e3{ 3 };
auto && rref = std::move(e3);
vv.push_back(rref); // call push_back(const Elem &);
// case 4
Elem e4{ 4 };
vv.push_back(std::move(e4)); // call push_back(Elem &&);
return 0;
}
In case 3, the type of rref
is rvalue reference, and its value category is lvalue
, and calls push_back(const Elem &)
.
In case 4, According to Effective Modern C++ Item 23, an implementation of std::move
is something like
// C++ 14
template<typename T>
decltype(auto) move(T&& param)
{
using ReturnType = remove_reference_t<T>&&;
return static_cast<ReturnType>(param);
}
The type of std::move(e4)
is Elem &&
, and its value category is prvalue
, calls push_back(Elem &&)
.
So a lvalue
of T&&
matches const T &
, and a prvalue
of T&&
matches T&&
, what do type and value category of an expression actually do during overload resolution between T
, const T &
and T &&
?
Sorry for not describing my problem clearly. As so many links said that, if an argument's value category is prvalue
, the function with T&&
will be called; value category is lvalue
, the function with const T &
will be called.
Can I simply say that argument's type is used for overload resolution, while value category is checked for reference binding when parameter's type is a reference?
rref
is an lvalue since it has a name, sopush_back(const Elem &)
is called. Themove
into a named variable is useless, but if you insist on it you can change your code to:And then
push_back(Elem &&)
is called. Or just do what you did in case 4.