0

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

joergbrech
  • 2,056
  • 1
  • 5
  • 17
  • A string literal, such as `"Hello, world!"` are lvalue expression from [cppreference](https://en.cppreference.com/w/cpp/language/value_category) or from this [Why are string literals l-value while all other literals are r-value?](https://stackoverflow.com/questions/10004511/why-are-string-literals-l-value-while-all-other-literals-are-r-value) – Jason Jul 26 '22 at 08:01
  • Ah thanks! Yes that helps. But I still don't know how I would take up ownership of a string literal in the code example. So I suppose I was actually asking two questions: Why are string literals lvalue (answered) and how to fix my code :) – joergbrech Jul 26 '22 at 08:07
  • You can specialize your template for string literals. See the second dupe [C++ specialized template function receiving literal string](https://stackoverflow.com/questions/49017404/c-specialized-template-function-receiving-literal-string) for example. – Jason Jul 26 '22 at 08:08
  • @AnoopRana I'm under the impression that numerals (number literals) are also stored in read only data and exposed as lvalues to a program [example](http://coliru.stacked-crooked.com/a/15894a5e7ec20e62) . Is that correct ? – Lorah Attkins Jul 26 '22 at 08:09
  • numbers like `2` or `500` etc are integer literals which are `rvalue`s( prvalue to be more exact) – Jason Jul 26 '22 at 08:10
  • Of course! The specialization would solve my problem. Thanks! – joergbrech Jul 26 '22 at 08:10

0 Answers0