This question may not have the best title but here is the code that will explain what I am trying to ask.
This code runs and prints "lvalue" but If I remove const
from MyPair's first type, it gives me the expected output, which is "rvalue". I would like to know what role const
plays here?
#include <iostream>
#include <utility>
#include <string>
using MyPair = std::pair<const std::string, int>;
void func(std::string&& str)
{
std::cout << "rvalue" << std::endl;
}
void func(const std::string& str)
{
std::cout << "lvalue" << std::endl;
}
template<typename T>
void func_forward(T&& p)
{
func(std::forward<T>(p).first);
}
void test(MyPair&& p)
{
func_forward(std::move(p));
}
int main()
{
test({"hello", 3});
return 0;
}
Nothing is being turned into a lvalue.
std::forward<T>(p).first
is in your example's instantiation is a rvalue (specifically xvalue) regardless of the const
. However, it's type will be const std::string
or std::string
depending on the choice of const
in the MyPair
type.
The problem is that your method of differentiating lvalues from rvalues with func
is incorrect, because the first overload of func
's parameter is not const
-qualified and so will only accept rvalues of non-const
std::string
type.
Your second func
overload on the other hand can accept any value category and const
-qualification because a const
lvalue reference is allowed to bind to lvalues as well as rvalues. So it will be chosen if first
is const
qualified, regardless of value category as the the only viable overload.
To fix your detection method use const std::string&&
instead of std::string&&
as parameter type in the first func
overload.