欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C++程序员应了解的那些事(68)非类型模板参数

程序员文章站 2022-07-12 22:57:47
...

模板除了定义类型参数,我们还可以在模板定义非类型参数
什么是非类型形参顾名思义,就是表示一个固定类型的常量而不是一个类型。
※ 固定类型是有局限的,只有整形,指针和引用才能作为非类型形参
※ 而且绑定到该形参的
实参必须是常量表达式,即编译期就能确认结果。

非类型形参的局限:
1.浮点数不可以作为非类型形参,包括float,double。具体原因可能是历史因素,也许未来C++会支持浮点数;
2.类不可以作为非类型形参;
3.字符串不可以作为非类型形参;
4.整形,可转化为整形的类型都可以作为形参,比如int,char,long,unsigned,bool,short(enum声明的内部数据可以作为实参传递给int,但是一般不能当形参);
5.指向对象或函数的指针与引用(左值引用)可以作为形参。

 
非类型实参的局限:
1.实参必须是编译时常量表达式,不能使用非const的局部变量,局部对象地址及动态对象;
2.非const的全局指针,全局对象/全局变量(下面可能有个特例)都不是常量表达式;

3.由于形参的已经做了限定,字符串,浮点型即使是常量表达式也不可以作为非类型实参;
备注:常量表达式基本上是字面值以及const修饰的变量
*************************************************************************************************

<例1-整型>
const int r = 777;
template<int  r>
void R()
{
    cout << r << endl;
}
----------------------
int main()
{
    R<666>();
    R<r>();

    const  int r2 = 888;
    R<r2>();

    int  r3 = 999; //局部变量  
    //  R<r3>();   //错误:包含非静态存储持续时间的变量不能用作非类型参数(非const的局部变量)
}
<例2-指针>
char   x1[] = "saaaa";//全局变量 
char * x2   = "qweqeq";//全局变量 
char * const  x3 = "qweqeq";//全局变量 指针常量 
(warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings] 修改为:const char *x2 = "qweqeq";)
template<typename T, char* x>
void X(T  t)
{
    cout << t << ", " << x << endl;
};
---------------------------------
int main()
{
    X<int, x1>(3);
    // X<int, x2>(4);  // 错误: 应为编译时常量表达式 
    // X<int, x3>(5);  // 错误:非const的全局指针! 涉及带有内部链接的对象的表达式不能用作非类型参数 

    char *x4 = "adsas";//局部变量,告警:ISO C++ forbids converting a string constant to 'char*'
    // X<int, x4>(6);//  错误: 包含非静态存储持续时间的变量不能用作非类型参数 
    // X<int, "sdfsd">(7);//错误:字符串,浮点型即使是常量表达式也不可以作为非类型实参
}
<例3-整型>
template<int a>
void  A(const char(&p)[a])
{
    std::cout << "size : " << a << "    " << p << std::endl; 
}
-----------------------------------------
int main()
{
    A("hello") ;
    A<6>("hello");
}
<例4-引用>
struct Y {};
Y y;
template<const Y& b>
struct Z {};

int q = 1;
template<const int& q> 
struct Q {};
--------------------
int main()
{
    Z<y> z;
    Q<q>  q1;
}
<例5-数组指针>
int b[5] = {11,22,33,44};
template<int(&pa)[5]> 
void B()
{
    cout << pa[1] << endl;
};
---------------------------
int main()
{
    B<b>(); // ok: no conversion
}
<例6-函数指针>
void f(int  a)
{
    cout << "a  is  "<<a << endl;
}
template<void(*pf)(int)>
void C()
{
    pf(111); 
};
----------------------------------
int main()
{
    C<&f>(); // ok: overload resolution selects f(int)
}
<例7-模板 模板参数>
template<typename T> class N { public:   int x; };   // primary template 通用模板
template<class T> class N<T*> { public:   long x; }; // partial specialization 偏特化

template<  template<typename> class V   > 
class  M
{
public:
    V<int>  y; // uses the primary template
    V<int*> z; // uses the partial specialization
};
------------------------------------
int main()
{
    M<N> m = M<N>(); //显示地调用内建类型的缺省构造函数
    cout << m.y.x << endl;
}

 

相关标签: 程序员应知应会