Search code examples
c++templatesstring-literalsforwarding-reference

Pass string literal to template function


I try to specialize a template function for a few types, one of them is const char*.

template<typename T = const char*>
void f(T&&);

template<>
void f<int>(int&& k) { std::cout << "Now in int fcn (" << k << ")!\n"; }

template<>
void f<const char*>(const char* && k) { std::cout << "Now in cc* fcn (" << k << ")!\n"; }

int main() {
  f<int>(5);
  f("HELLO");

  return 0;
}

But when I execute f("HELLO"), I get the following error:

main.cpp:(.text+0x32): undefined reference to `void f<char const (&) [6]>(char const (&) [6])'

How do I make it interpret "HELLO" as a const char* and not an array? If I specialize for arrays I need one for each array size?

Also, the generic template function catches f("HELLO"):

template<typename T>
void f(T&& k) { /* Definition... */ }

Will it create one specialization for every array size I need or does it somehow cast the string literal to "const char*"?


Solution

  • A string literal is not a const char*. A string literal has the type const char[N] where N is the number of characters plus a null terminator. That means when you call the function T gets deduced to const char[6], which does not match any of the specializations so the main template is used. Since you have not defined the main template, you get a linker error about the definition missing.

    You can add an overload of the function to handle char arrays and string literals by using

    template<std::size_t N> void f(const char (&arr)[N]) { stuff; }
    

    Yes, it will stamp out a function for each sized array, but that's just a little extra compilation time, you only need to write the body once.


    You should also have a read of Why Not Specialize Function Templates?. In the article it details why function template specializations don't always work like you want them to and that they don't participate in overload resolution. Generally you should overload instead of specializing.