c++模板编程-非类型模板参数

非类型模板参数

模板参数不一定非得是某种具体的类型,也可以是常规数值。和类模板使用类型作为参数类似,可以使代码的另一些细节留到被使用时再确定,只是对非类型模板参数,待定的不再是类型,而是某个数值。在使用这种模板时需要显式的指出待定数值的具体值,之后代码会被实例化。

template <typename T, int size>
class Container
{
public:
    std::array<T, size> arr;
};

Container<int, 5> c{1, 2, 3, 4, 5};
for(int i : c.arr)
{
    cout << i << endl;
}

非类型模板参数也可以是默认值

template <typename T, int size = 5>
class Container
{
public:
    std::array<T, size> arr;
};

Container<int> c{1, 2, 3, 4, 5};
for(int i : c.arr)
{
    cout << i << endl;
}

 

函数模板的非类型参数
template <int value, typename T>
T add(T t)
{
    return t + value;
}

//两种都可以实例化
cout << add<1, double>(2.1) << endl;
cout << add<1>(2.1) << endl;

可以通过传入的非类型模板参数推断出返回类型:

template <auto value, typename T = decltype(value)>
T add(T t)
{
    return t + value;
}

add<1>(2); //实例化 int add(int),返回 3

可以通过如下方式确保传入的非类型模板参数的类型和类型参数的类型一致:

template <typename T, T value = T{}>
T add(T t)
{
    return t + value;
}

add<int, 1.1>(2) //错误,非类型模板参数和模板参数类型不一致
add<int, 1>(2)   //正确

 

非类型模板参数的限制

使用非类型模板参数是有限制的。通常它们只能是整形常量(包含枚举),指向objects/functions/members 的指针,objects或者functions的左值引用,或者是std::nullptr_t(nullptr decltype 出来的类型)。

浮点型数或者 class 类型的对象都不能作为非类型模板参数使用(c++20标准支持):

template <double value> //错误
void fun(){}

template <string s> //错误
void fun(){}

当传递对象的指针或者引用作为模板参数时,对象不能是字符串常量,临时变量或者数据成员以及其它子对象;在cpp17之前,c++版本的每次更新都会放宽以上限制,因此还有一些针对不同版本的限制:

  • c++11 对象必须要有外部链接
  • c++14 对象必须是外部链接或者内部链接
template <char const* name>
class Test {};
Test<"hello"> t; //错误,内外链接都没有

使用技巧规避

template <char const* name>
class Test {};

extern char const externalLink[] = "hello";
char const internalLink[] = "hello";

Test<externalLink> external; //正确、有外部链接
Test<internalLink> internal; //正确,有内部链接    

static char const noLink[] = "hello";
Test<noLink> no; //c++17 前错误,内外链接都没有

非类型模板参数可以是任何编译器表达式。比如:

template<int i, bool b>
class T {};
T< sizeof(int), sizeof(int) == 4 > t;

需要注意的是,如果在表达式中使用了 operator >,就必须将相应表达式放在括号中,否则 > 会被语法解析为模板参数列表末尾的尖括号,导致错误

T< sizeof(int), sizeof(int) > 4 > t;   //大于号导致语法解析错误
T< sizeof(int), (sizeof(int) > 4) > t; //正确,表达式在括号中

 

用 auto 作为非类型模板参数的类型

从 C++17 开始,可以使用auto作为类型模板参数的类型

template<typename T, auto size>
class Container 
{
public:
    using sizeType = decltype(size);
	std::array<T, size> arr;
	
	auto getSize() const // c++14 后可使用返回类型推导 auto getSize()
	{
		return size;
	}
};

Container<int, 5> c{ 1, 2, 3, 4, 5 };
Container<int, 5u> cu{ 1, 2, 3, 4, 5 };

auto cSize = c.getSize();
auto cuSize = cu.getSize();

//验证类型是否相同, c 为int, cu 为 unsigned int
if ( std::is_same< decltype(cSize), decltype(cuSize) >::value)
{
	cout << "Same type." << endl;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

为啥不吃肉捏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值