c++无类型参数模板(non-type template parameter) 与 无具名空间 static

本文详细解析了C++中无类型的模板参数的使用规范及限制条件,包括合法的参数类型、参数传递的要求以及常见的错误案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

     无类型的模板参数:

     C++的template可以传入普通的参数,和平时使用普通的函数参数有点相似,但又有很大的不同。
    这种形式的模板一般是用来初始化类的数组成员的大小例如下面有的代码:


     template<int size>
     class CTest {
         int m_data[size];
     };
    void main() {
        CTest<10> obj;// 将obj对象的成员 数值m_data大小初始为10 ,是不是很简单?
     }


     用整型来作为无类型模板参数使用起来确实simple,那么换其他类型试试?

    
收集了一点资料稍微整理了下,看看下面资料怎么说的:
      a non-type template-parameter shall have one of the following types

      (无类型模板参数应该是下面所列举的类型):
     1. integral or enumeration type(整型 或者 枚举)
     2. pointer to object or pointer to function(对象的指针或函数指针,其实还包括基本类型的指针)
     3. reference to object or reference to function(对象的引用或者函数的引用)
     4. Attention :The C++ standard does not allow floating point non-type template parameters
   (注意:c++标准规定浮点型不能作为无类型模板的参数,但他们的引用和指针是允许的。例如 float,double)


   你已经知道了应该传入什么类型参数,说真的,这还远远不够。
   a template-argument for a non-type, non-type template-parameter shall be one of:
     1.对于整型参数:应该传入一个常量或者枚举值
       an integral constant-expression of integral or enumeration type
     2.对象的指针或者函数的地址因该具有外部连接属性,具有内部链接属性将报错;

       the address of an object or function with external linkage
     3.可以是一个引用类型的参数参数 例如: template<int&> void func() {}; 
       the corresponding template-parameter is a reference

 

     下面再来看看non-type template-parameter 有关的错误描述:
      error c2970: 
      an expression involving objects with internal linkage cannot be used as a non-type argument

     (涉及到对象内部连接的表达式不能作为 non-type argument)

      error c2975:
      expected compile-time constant expression

      (需要一个编译期常量表达式)

      error c2971:
      a local variable cannot be used as a non-type argument,

      You cannot use the name or address of a local variable as a template argument.

    (局部变量不能作为non-type argument,

        这里主要是指:指针和引用,但是局部整型常量除外,所以下面的代码是ok的。

 

 

  1. template<int>  
  2. void fun1()     {}  
  3.       
  4. template<int*>  
  5. void fun1_1()   {}  
  6.   
  7. template<int&>  
  8. void fun1_2()   {}  
  9.   
  10. template<char*>  
  11. void fun2()     {}  
  12.   
  13. template<char>  
  14. void fun3()     {}  
  15.   
  16. struct  CA  {};  
  17. union   Ua  {};  
  18.   
  19. // 浮点数 例如float,double,是不能作为 non-type template parameter的  
  20. //template<float>  
  21. //void fun4()   {}  
  22.   
  23. // 要使用类的或者联合的指针 或者引用  
  24. //template<CA>              
  25. //void fun4()   {}  
  26.   
  27. //template<Ua>  
  28. //void fun5()   {}  
  29.   
  30. template<CA*>           
  31. void fun4_1()   {}  
  32.   
  33. template<CA&>           
  34. void fun4_2()   {}  
  35.   
  36. template<Ua*>  
  37. void fun5_1()   {}  
  38.   
  39. template<Ua&>  
  40. void fun5_2()   {}  
  41.   
  42. //------------------------------------------------------------------------//  
  43. int         idata3 = 20;        // 外部链接  
  44. const int   idata2 = 9;         // 内部链接  
  45.   
  46. CA          impCa1;             // 外部链接  
  47. const CA    impCa2;             // 内部链接  
  48. static CA   impCa3;             // 内部链接  
  49.   
  50. Ua          impUa1;             // 外部链接  
  51. const Ua    impUa2;             // 内部链接  
  52. static Ua   impUa3;             // 内部链接  
  53.   
  54. const char  str3[] = "str";     // 内部链接  
  55. static char str4[] = "str";     // 内部链接  
  56. char        str5[] = "str";     // 外部链接  
  57.   
  58. char*       str6   = "str";     // 外部链接  
  59. const char* str7   = "str";     // 内部链接  
  60. charconst str8   = "str";     // 内部链接  
  61. const charconst str9   = "str";   // 内部链接  
  62.   
  63. const char  chr    = 'x';       // 内部链接  
  64. void funtest(int);  
  65. void funtest( int )     {}  
  66.   
  67. static void funtest2(int);  
  68. void funtest2( int )    {}  
  69.   
  70. typedef void (*ptr_func)(int);  
  71.   
  72. template<ptr_func>  
  73. void fun6()     {}  
  74.   
  75. ptr_func pfun2 = &funtest;  
  76. const ptr_func pfun3 = &funtest;  
  77. static const ptr_func pfun4 = &funtest;  
  78.   
  79.   
  80. int _tmain(int argc, _TCHAR* argv[])  
  81. {  
  82.   
  83.     int i = 12;  
  84.     //const int idata = i;  // error 2971 局部变量不能用作非类型参数  
  85.     const int idata = 10;   // 局部常量 ok  
  86.     fun1<idata>();            // ok  
  87.       
  88.     int idata4 = 20;  
  89.     //fun1_1<&idata2>();  // error c2970 涉及到对象内部连接的表达式不能作为 non-type argument.  
  90.     //fun1_1<&idata4>();  // error c2971   
  91.     fun1_1<&idata3>();        // ok  
  92.       
  93.     //fun1_2<idata2>();       // error c2970  
  94.     //fun1_2<idata4>();       // error c2971   
  95.     fun1_2<idata3>();     // ok  
  96.       
  97.     char        str1[]  = "string";  
  98.     const char* str2    = "string";  
  99.     //fun2<str1>();           // error c2971  
  100.     //fun2<str2>();           // error c2971  
  101.     //fun2<str3>();           // error c2970   
  102.     //fun2<str4>();           // error c2970  
  103.     //fun2<"test">();     // error c2762 模板参数的表达式无效,为什么会无效?字符串"test"具有内部链接? 问题1。  
  104.     fun2<str5>();         // ok  
  105.     //fun2<str6>();           // error 2975 需要一个编译期常量表达式  
  106.     //fun2<str7>();           // error 2975  
  107.     //fun2<str8>();           // error c2971  
  108.     //fun2<str9>();           // error c2971  
  109.   
  110.     //fun3<str2[1]>();        // error 2975 需要一个编译期常量表达式  
  111.     //fun3<str3[0]>();        // error 2975 为什么str3[0]不是编译期常量,问题2  
  112.     fun3<'x'>();          // ok  
  113.     fun3<chr>();          // ok  
  114.   
  115.     // ok  
  116.     fun4_1<&impCa1>();  
  117.     fun4_2<impCa1>();  
  118.   
  119.     // ok  
  120.     fun5_1<&impUa1>();  
  121.     fun5_2<impUa1>();  
  122.   
  123.     //  
  124.     ptr_func pfun = &funtest;  
  125.     //fun6<pfun>();       // error c2971  
  126.     //fun6<pfun2>();  // error c2975  
  127.     //fun6<pfun3>();  // error C2970  
  128.     //fun6<&pfun4>(); // error C2970  
  129.     fun6<&funtest>(); // ok  
  130.     fun6<&funtest2>();  
  131.   
  132.         return 0; 

 

记得以前一个同事问我为什么程序里使用了 anonymouse namespace ,想了想 就回答说其实就是保持局部性(这也是我的目的),然后就有人说为什么不用static,嗯 似乎这两个东西乍一看没什么区别,自己便Google了一下,发现有一个原因就是 anonymousenamespace 里的 member 都是有外部链接的,只不过永远都不能被外部link到!而 static 就明确为根本没有外部链接!此时就出现问题了,在模板里无类型的参数必须是有外部链接的才可以,否则编译无法通;比如:
template <void fn()>
class Foobar
{};

namespace
{
void abc()
{
wcout<<_T(”abc”)<<endl;
};
}
static void efg()
{
wcout<<_T(”efg”)<<endl;
};
int _tmain(int argc, _TCHAR* argv[])
{
Foobar<abc>xyz //! ;这一行可以通过
Foobar<efg>rst; //! 注意这一行编译不过
return 0;
}
也有人认为使用 anon namespace比较好,因为static的方式被C++98标准所批评,呵呵 总体来说 ,其实你完全可以用anony namespace代替static

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值