第三章 非类型模板参数

1.函数的非类型模板参数

template<int val, typename T = int>void trans() {

	std::cout << val << std::endl;
}

2.也可以从第一个参数推导第二个

template<auto Value, typename T = decltype(Value)>void func() {
	std::cout << T{} << std::endl;

}

3.非类型模板参数的限制

  1. 类型一般只能为常量值(no constexpr),指向类(类成员)的指针,函数指针,左值引用对于对象或者函数
template<void(*ptr)(int), typename T = decltype(ptr)>void func(int a) {//传递函数指针
	ptr(a);
}
//传递类指针
struct A{}
template<A*a>void func(){
}
//传递类成员指针
template<typename T,typename void(A<T>::*func)() > void function() {
	func();
}//这个地方有问题,无法调用function
//传递左值引用
struct T{};
template<T& t>void func() {


}

注意传递指针或引用时不要传递字符串

template<const char*name>class A{};
//无法使用

4.通过模板参数拒绝非法实例化

5.非类型模板参数注意点

  1. 之前已经介绍过,非类型模板参数只能是常量值,指针,左值引用,但是经测试(msvc2022)在如下代码
template<decltype(auto) N>class A{
}
//这里除了常量存储区的常量还可以是静态存储区的变量static int a;A<(a)>b;ok!

2.建议尽量别使用char*作为非类型模板参数,经测试无法使用

3.在1的例子中N会在类中转化为引用

4.经测试发现在msvc下,非类型模板参数无法使用decltype代码如下

template<int A>class refenceTest {
public:
	void func() {
		if (std::is_same_v(decltype(A), int&)) {
			std::cout << "decltype 会转化为引用" << std::endl;
		}
	}
};//报错:编译器内部错误,但是好像在gdb下没有这个问题

5.const区分是常量,但并未区分编译时常量和运行时常量,所以推荐模板中用constexpr声明常量和表达式。(虽然编译器有可能报内部错误)