Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does the type deduction work for string literals in C++?

In C++ if I have a generic function:

template <typename T>
void func(T& s)
{
    std::cout << "in generic\n";
    std::cout << typeid(s).name();
}

T will get deduced to typeid(s).name().

But how come if I do:

func("test");

That generic function works, but this one doesn't:

void func(const char*& s)
{   
    std::cout << "in overloaded\n";
    std::cout << typeid(s).name();
}

I know that it'll work if I change const char*& to const char* or const char* const&in the overloaded function's signature, and that if I want to pass an argument to the overloaded function it must be non-temporary. I just don't understand what happened to T&, isn't it supposed to turn into const char*& after the deduction?

like image 699
Pavel Avatar asked Oct 16 '14 07:10

Pavel


2 Answers

String literals are arrays of const characters. So in the case of the template function called like this:

func("test");

T is deduced as char const[5]. And s is a reference to the string literal, and its type is char const (&)[5]. That is, a reference to an array of 5 const char.

like image 134
Benjamin Lindley Avatar answered Sep 29 '22 04:09

Benjamin Lindley


The type of "test" is const char[5]. When calling a function template and using an argument to deduce a parameter of reference type, the array-to-pointer conversion does not happen. So the generic function deduces T to be const char[5] - you can see that the output for "test" and for a const char* differs:

template<typename T>
void func(T& s){

    std::cout << "in generic\n";
    std::cout << typeid(s).name() << '\n';
}

int main()
{
    func("test");
    const char *c = "test";
    func(c);
}

GCC output:

in generic
A5_c
in generic
PKc

On the other hand, in the non-generic function, you want a reference to a non-const pointer to const char. However, as the type of "test" is const char[5], it has to undergo the array-to-pointer conversion, which means that the resulting const char* is a temporary (an rvalue). As such, it cannot bind to a reference to non-const.

like image 25
Angew is no longer proud of SO Avatar answered Sep 29 '22 04:09

Angew is no longer proud of SO