我试了下面的代码。
template <int VAL>
void printVAL()
{
for(int i=0;i<VAL; i++){
cout << " i value is "<<i<<endl;
}
}
实例化:printVAL<100> ()
当我使用(std::string s)作为非类型模板参数时,编译器向我大喊以下错误
"class std::basic_str<char>' is not a valid type for a template non-type parameter.
我所知道的是我们应该只使用常数整数值。
问题:
1)为什么我们不应该使用std::string,有什么问题吗?
2)"指向具有外部链接的对象的指针可以使用"的含义是什么?我能得到它的样例代码吗?
根据14.1/4,
非类型模板参数必须是以下类型之一(可选的cv限定):
- 整型或枚举型,
- 指向对象或指向函数的指针,
- 左值指向对象或左值指向函数
- 指针指向成员,
std::nullptr_t
.
你的std::string
不是这些
只能传递整型值作为非类型模板参数。这是语言的局限性。您可能需要以下内容:
template<class T>
void printVAL(const T& t)
{
for (auto& x : t) {
cout << " x value is "<< x << 'n';
}
}
这将打印任何东西:容器,字符串,数组等。
有两种类型的模板:泛型模板和指定类型模板。
泛型类型的模板,如
template<typename T>
或
template<class T>
这些模板几乎可以用于任何类型。这些类型的实际使用可能会限制实际可以使用的类型。
具有指定类型的模板就像你问题中的模板:
template<int VAL>
只能用于与指定类型匹配的模板实参。在这种情况下,只能使用整数字面值。
1)为什么我们不应该使用std::string,有什么问题吗?
编译器必须能够在编译时推断和替换模板形参。这不能用std::string
对象完成,它可以(通常)在运行时改变。
参见此问题& a。
2)"指向具有外部链接的对象的指针可以使用"的含义是什么?我能得到它的样例代码吗?
这是因为具有静态存储时间的对象(即声明了extern
的对象)的地址是一个常量表达式。
n3337 5.19/3,强调我的:
字面常量表达式是字面类型的右值核心常量表达式,但不是指针类型。一个整型常量表达式是整型或无作用域枚举类型的文字常量表达式。【注:这样的表达式可以用作数组边界(8.3.4,5.3.4),位域长度(9.6),枚举数initializ-如果底层类型不固定(7.2),则作为空指针常量(4.10)和对齐(7.6.2)。端类型T的转换常量表达式是隐含转换为类型T的字面常量表达式;在文字常量表达式和隐式转换中允许隐式转换(如果有的话)的地方序列只包含用户定义的转换,左值到右值的转换(4.1),整型提升(4.5),以及除窄化转换(8.5.4)以外的整型转换(4.7)。[注:可以使用这样的表达作为case表达式(6.4.2),如果底层类型是固定的(7.2),作为枚举数初始化器,以及作为整型或枚举非类型模板参数(14.3)。引用常量表达式为左值指定具有静态存储时间的对象或函数的核心常量表达式。一个地址常量表达式是指针类型的右值核心常量表达式,其计算结果为an的地址对象的静态存储时间,转换为函数的地址,或空指针值,或右值核心std::nullptr_t类型的常量表达式。总的来说,字面常量表达式,引用常量表达式和地址常量表达式称为常量表达式。
请求示例:
#include <iostream>
#include <string>
extern std::string str; // not really neccesary
std::string str;
template<std::string* ptr>
struct S {
S() { std::cout << ptr->length() << 'n'; }
~S() { std::cout << *ptr; }
};
int main()
{
S<&str> s;
str = "Hello world!";
}