非类型模板参数的限制

C++非类型模板参数的限制在 C++ Templates中有两条:
1. 参数是常整数(包括枚举值)
2. 指向外部链接对象的指针
英文的原文(摘录自C++ Templates 4.3)如下:

Note that nontype template parameters carry some restrictions. In general, they may be constant integral values (including enumerations) or pointers to objects with external linkage.

这里面说的有点费解,对这里面的论述稍微做点注解。

1. 对条款1的具体阐述

  1. 参数指的是实参,在函数中关于参数的术语有parameter和argument两种,前者指的是函数的形参,而后者是指真正传入的参数值,如下所示:
//这里的参数a和b指的是形参(parameter)
int add(int a, int b)
{
    return a + b;
}

int main()
{
    int c = add(1, 2);  //这里传入的1,2是真正的参数,是实参(argument)
}

因此上面的关于非类型模板实参的描述应该是:实参是整型或者枚举类型。举例如下:

template<int intVal>
int addValue(int x)
{
    return x + intVal;
}

这个示例就是一个正确的非类型模板参数的函数模板,它的模板参数的定义书写方式和我们在定义普通的int类型变量是没有任何差别。

当我看到条款1时,我的第一反应是这个示例是不对的,应该是常量或者枚举值呀。写成下面的方式:

template <int const intVal>
int addValue(int x)
{
    return x + intVal;
}

事实上这两种写法都是对的,后一种写法对intVal有一些限制,intVal必须是常量因此不能在函数体内修改它。
也就是说我第一反应的理解并不正确,我的第一反应是对形参的要求,但是实际上这个条款是对实参的要求,如下所示:

int main()
{
    //模板实参是字面值常量(正确)
    int v = 1;
    int w = addValue<5>(v);
    std::cout << w << std::endl;

    //模板实参是const定义的常量(正确)
    const int constInt4 = 4;
    int u = addValue<constInt4>(v);
    std::cout << u << std::endl;

    //模板实参是枚举值(正确)
    enum AEnum
    {
        A = 65,
        B = 66
    };
    int a = addValue<A>(v);
    std::cout << a << std::endl;

    //模板参数是int类型的变量,不是常量(编译出错)
    int int6 = 6;
    int t = addValue<int6>(v);
    std::cout << t << std::endl;
}

2. 对条款2的具体阐述

指向外部链接对象的指针,这里有两层含义:1.非类型模板形参可以是指针;2.指针指向的对象必须是具有外部链接性的对象(另外对象必须必须是编译时常量表达式)
这里面涉及到外部链接和内部链接的概念,这些和C/C++中的编译过程和编译单元相关,可以查看参考文献中的文章。参考文献3种详细的提及了对实参和形参的要求:

这里要强调一点,我们对于非类型形参的限定要分两个方面看
1.对模板形参的限定,即template<>里面的参数
2.对模板实参的限定,即实例化时<>里面的参数

【对形参的要求】
1.字符串不可以作为非类型形参
2.整形,可转化为整形的类型都可以作为形参,比如intcharlongunsignedboolshortenum声明的内部数据可以作为实参传递给int,但是一般不能当形参)
3.指向对象或函数的指针与引用(左值引用)可以作为形参

【对实参的要求】
1.**实参必须是编译时常量表达式,不能使用非const的局部变量,局部对象地址及动态对象**[非常重要]
2.非Const的全局指针,全局对象,全局变量都不是常量表达式。
3.由于形参的已经做了限定,字符串,浮点型即使是常量表达式也不可以作为非类型实参
备注:常量表达式基本上是字面值以及const修饰的变量

3. 其他限制条件

3.1 非类型模板形参不能为浮点类型

模板参数(形参)不能是浮点类型,也就是下面的代码编译会出错

//形参不能为浮点类型
//在C++11、C++14中测试依然报错
template <double VAT>     
double process(double v)
{
    return v * VAT;
}

C++ Templates一书作者提到这一特性的实现是可以实现的,未来C++的标准可能会支持,但是在C++11和C++14种仍然是不支持的。

3.2 非类型模板形参不能为类(class)

下面的代码编译会出错:

template <std::string name>
class MyClass 
{

};

参考文献

  1. C++ Templates: The Complete Guide
  2. static inline与内部、外部链接对象
  3. 模板非类型形参的详细阐述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值