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).firstis in your example's instantiation is a rvalue (specifically xvalue) regardless of theconst. However, it's type will beconst std::stringorstd::stringdepending on the choice ofconstin theMyPairtype.The problem is that your method of differentiating lvalues from rvalues with
funcis incorrect, because the first overload offunc's parameter is notconst-qualified and so will only accept rvalues of non-conststd::stringtype.Your second
funcoverload on the other hand can accept any value category andconst-qualification because aconstlvalue reference is allowed to bind to lvalues as well as rvalues. So it will be chosen iffirstisconstqualified, regardless of value category as the the only viable overload.To fix your detection method use
const std::string&&instead ofstd::string&&as parameter type in the firstfuncoverload.