Cpp Notes

ch12.string_literals_as_template_parameters

C++17 - The complete guide, Ch 12: Dealing with String Literals as Template Parameters

12.1 Using Strings in Templates

  • Over time, the different versions of C++ relaxed the rules for what can be used as template parameters, and this happened again with C++17.

  • Templates now can be used without having to be defined outside the current scope.

  • Non-type template parameters can be only constant integral values (including enumerations), pointers to objects/functions/members, lvalue references to objects or functions, or std::nullptr_t

  • For pointers, before C++17, external or internal linkage was required. However, since C++17, you can have pointers with what is called “no linkage.”

  • However, you still cannot pass string literals directly. For example:

template <const char* str>
class Message {
  //...
};

extern const char hello[] = "Hello World!";  // external linkage
const char hello11[] = "Hello World!";       // internal linkage

void foo() {
  Message<hello> msg;                            // OK (all C++ versions)
  Message<hello11> msg11;                        // OK since C++11
  static const char hello17[] = "Hello World!";  // no linkage
  Message<hello17> msg17;                        // OK since C++17
  Message<"hi"> msgError;                        // ERROR
}
  • That is, since C++17, you still need two lines to pass a string literal to a template. However, you can have the first line in the same scope as the class instantiation.
  • This ability also solves an unfortunate constraint: While it has been possible to pass a pointer to a class template since C++11:
template <int* p>
struct A {};
int num;
A<&num> a;  // OK since C++11
  • It was not possible to use a compile-time function that returned the address but this is now supported:
int num;
//...
constexpr int* pNum() { return &num; }
A<pNum()> b;  // ERROR before C++17, now OK