When trying to write a function that behaves differently for lvalue references and rvalue references I noticed, that C strings seem to always be considered as lvalue references.
#include <iostream>
template <typename T>
struct Holder {
T value;
};
template <typename T>
Holder<T> some_function(T&& t) {
std::cout<< "overload T&&, "
<< typeid(T).name()
<< std::endl;
return {std::move(t)};
}
template <typename T>
Holder<T*> some_function(T& t) {
std::cout<<"overload T&, "
<< typeid(T).name()
<< std::endl;
return {&t};
}
Here, the returned Holder
holds a pointer to the argument if some_function
is passed an lvalue reference and it moves the argument otherwise.
When calling some_function
on std::string
it behaves as expected. But when I pass const char*
strings to it, it always consideres the argument to be an lvalue-reference:
int main()
{
std::string x = "lvalue string";
auto holder_string_lvalue = some_function(x);
auto holder_string_rvalue = some_function(std::string("rvalue string"));
const char* y = "lvalue cstring";
auto holder_cstring_lvalue = some_function(y);
auto holder_cstring_rvalue = some_function("rvalue cstring");
return 0;
}
Output:
overload T&, NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
overload T&&, NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
overload T&, PKc
overload T&, A15_c
I don't understand the fourth line in this. Also, the code should now have a Holder
with an invalid pointer holder_cstring_rvalue
, does it not?
How would I make sure Holder
never points to a temporary object for arbitrary T
, including c strings?
Compiler explorer link: https://godbolt.org/z/EMfETYc7e