第十二章 String作为模板参数
一直以来,C++对于哪些类型可以用于模板参数的规则在逐渐放松,C++17更是如此。即使在当前作用域外定义的模板,也可以使用它作为模板参数。
12.1 在模板中使用string
非类型模板参数只能是整数类型(包括枚举),指向对象、函数、成员的指针,对象或者函数的左值引用,以及std::nullptr_t
(nullptr的类型)。
对于指针,链接是必须的,这意味着你不能直接传递字符串字面值。然而,从C++11(译注:这里原文是C++17,可能是笔误)开始,你可以传一个内部链接(internal linkage)的指针。比如
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
}
也就是说,从C++17开始,你仍然需要写两行代码来传字符串字面值给模板,但是现在第一行可以放到和类实例化相同的作用域。 这种能力解决了一个很不幸的约束:从C++11开始你可以传指针给类模板:
template<int* p> struct A {
};
int num;
A<&num> a; // OK since C++11
但你不能使用返回一个地址的编译时函数作为模板参数,但是C++17开始允许这么做了:
int num;
...
constexpr int* pNum() {
return #
}
A<pNum()> b; // ERROR before C++17, now OK
12.2 后记
对于所有非类型模板参数允许常量求值这种能力首先由Richard Smith在https://wg21.link/n4198中提出。最后的公认措辞是由Richard Smith在https://wg21.link/n4268中给出。