C++实现模板中的非类型参数的方法

非类型模板参看,顾名思义,模板参数不限定于类型,普通值也可作为模板参数。在基于类型的模板中,模板实例化时所依赖的是某一类型的模板参数,你定义了一些模板参数(template<typename T>)未加确定的代码,直到模板被实例化这些参数细节才真正被确定。而非类型模板参数,面对的未加确定的参数细节是指(value),而非类型。当要使用基于值的模板时,你必须显式地指定这些值,模板方可被实例化。

在函数模板中使用非类型参数

#include<iostream>
using namespace std;
//在函数模板中使用非类型参数
template<class T>void Swap(T &a, T &b);
template<typename T, unsigned N>void Swap(T (&a)[N],T (&b)[N]);

template<typename T, unsigned N>void printArray(T (&arr)[N]);

int main(){
 int m = 10, n = 90;
 Swap(m,n);
 cout << "m = " << m << ", n = " << n << endl;

 int a[5] = { 1, 2, 3, 4, 5 };
 int b[5] = { 10, 20, 30, 40, 50 };
 Swap(a, b);
 printArray(a);
 printArray(b);
 return 0;

}

template<class T> void Swap(T &a,T &b){
 T temp = a;
 a = b;
 b = temp;
}

template<class T, unsigned N> void Swap(T (&a)[N],T (&b)[N]){
 T temp;
 for (int i = 0; i < N;i++){
 temp = a[i];
 a[i] = b[i];
 b[i] = temp;
 }
}

template<typename T, unsigned N>void printArray(T (&arr)[N]){
 for (int i = 0; i < N;i++){
 if (i == N-1){
  cout << arr[i] << endl;
 }
 else{
  cout << arr[i] << ", ";
 }
 }
}

在类模板中使用非类型参数

#include<iostream>
#include<cstring>
#include<cstdlib>
using namespace std;

//动态数组实现,在类模板中使用非类型参数
template<typename T,int N>
class Array{
public:
 Array();
 ~Array();
public:
 T & operator[](int i);//重载下标运算符
 int length() const{ return m_length; }//获取数组长度
 bool capacity(int n);//是否可改变数组容量
private:
 int m_length;//数组当前长度
 int m_capacity;//当前内存容量
 T *m_p;//指向数组内存的指针
};

template<typename T,int N>
Array<T, N>::Array(){
 m_p = new T[N];
 m_capacity = m_length = N;
}

template<typename T,int N>
Array<T, N>::~Array(){
 delete[] m_p;
}

template<typename T,int N>
T & Array<T, N>::operator[](int i){
 if (i<0||i>=m_length){
 cout << "Exception:Array index out of bounds!" << endl;
 }
 return m_p[i];
}

template<typename T,int N>
bool Array<T, N>:: capacity(int n){
 if (n>0){
 int len = m_length + n;
 if (len<=m_capacity){
  m_length = len;
  return true;
 }
 else{
  T *pTemp = new T[m_length + 2 * n*sizeof(T)];
  if (NULL==pTemp){
  cout << "Exception: Failed to allocate memory!";
  return false;
  }
  else{
  memcpy(pTemp,m_p,m_length*sizeof(T));
  delete[] m_p;
  m_p = pTemp;
  m_capacity = m_length = len;
  }
 }
 }
 else{
 int len = m_length - abs(n);
 if (len<0){
  cout << "Exception:Array length is too small!" << endl;
  return false;
 }
 else{
  m_length = len;
  return true;
 }
 }
}

int main(){
 Array<int, 5> arr;

 for (int i = 0, len = arr.length(); i < len;i++){
 arr[i] = 2 * i;
 }

 cout << "first print:" << endl;
 for (int i = 0, len = arr.length(); i < len;i++){
 cout << arr[i] << " ";
 }
 cout << endl;

 //扩大容量为增加的元素赋值
 arr.capacity(8);
 for (int i = 5, len = arr.length(); i < len;i++){
 arr[i] = 2 * i;
 }

 cout << endl;
 cout << "second print:" << endl;
 for (int i = 0, len = arr.length(); i < len;i++){
 cout << arr[i] << " ";
 }
 cout << endl;

 arr.capacity(-4);
 cout << "third print: " << endl;
 for (int i = 0, len = arr.length(); i < len; i++){
 cout << arr[i] << " ";
 }
 cout << endl;

 return 0;
}

非类型模板参数的限制

非类型模板参数是有类型限制的。一般而言,它可以是常整数(包括enum枚举类型)或者指向外部链接对象的指针。

浮点数和类对象(class-type)不允许作为非类型模板参数:

template<double VAL>      // ERROR: 浮点数不可作为非类型模板参数
double process(double v)
{
  return v * VAL;
}

template<std::string name>   // ERROR:类对象不能作为非类型模板参数
class MyClass
{}

稍作变通,我们即可使编译通过:

template<double* PVAL>
double process(const double& x)
{
  return x * (*PVAL);
}

template<const char* name>
class MyClass
{
  ...
}

这样可顺利通过编译,但如果想在当前文件中使用这两个模板,还需要动一些手脚:

double val = 10;
double res = process<&val>(20);   // ERROR: 表达式必须含有常量值

MyClass<"hello"> x;         // ERROR: 模板参数不能引用非外部实体

const char* s = "hello";
MyClass<s> x;            // ERROR: 表达式必须含有常量值

这里就点出另外一点注意事项,也就是非类型模板参数的限制,非类型模板参数可以是指针,但该指针必须指向外部链接对象,还记得在A.cpp中如何引用B.cpp中的全局变量吗,在A.hpp中使用extern关键字对外部变量加以引用。

// B.cpp
double val = 3.14159265;
char str[] = "hello";
// A.hpp
extern double val;
extern char str[];
// A.cpp
#include "A.hpp"

double res = process<&val>(10);
MyClass<str> x;

到此这篇关于C++实现模板中的非类型参数的方法的文章就介绍到这了,更多相关C++ 模板非类型参数内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++动态分配和撤销内存以及结构体类型作为函数参数

    C++动态分配内存(new)和撤销内存(delete) 在软件开发过程中,常常需要动态地分配和撤销内存空间,例如对动态链表中结点的插入与删除.在C语言中是利用库函数malloc和free来分配和撤销内存空间的.C++提供了较简便而功能较强的运算符new和delete来取代malloc和free函数. 注意: new和delete是运算符,不是函数,因此执行效率高. 虽然为了与C语言兼容,C++仍保留malloc和free函数,但建议用户不用malloc和free函数,而用new和delete运算

  • c++中拷贝构造函数的参数类型必须是引用

    在C++中, 构造函数,拷贝构造函数,析构函数和赋值函数(赋值运算符重载)是最基本不过的需要掌握的知识. 但是如果我问你"拷贝构造函数的参数为什么必须使用引用类型?"这个问题, 你会怎么回答? 或许你会回答为了减少一次内存拷贝? 很惭愧的是,我的第一感觉也是这么回答.不过还好,我思索一下以后,发现这个答案是不对的. 原因:如果拷贝构造函数中的参数不是一个引用,即形如CClass(const CClass c_class),那么就相当于采用了传值的方式(pass-by-value),而传

  • C++编程中将引用类型作为函数参数的方法指南

    有了变量名,为什么还需要一个别名呢?C++之所以增加引用类型, 主要是把它作为函数参数,以扩充函数传递数据的功能. 到目前为止我们介绍过函数参数传递的两种情况. 1) 将变量名作为实参和形参 这时传给形参的是变量的值,传递是单向的.如果在执行函数期间形参的值发生变化,并不传回给实参.因为在调用函数时,形参和实参不是同一个存储单元. [例]要求将变量i和j的值互换.下面的程序无法实现此要求. #include <iostream> using namespace std; int main( )

  • C++实现模板中的非类型参数的方法

    非类型模板参看,顾名思义,模板参数不限定于类型,普通值也可作为模板参数.在基于类型的模板中,模板实例化时所依赖的是某一类型的模板参数,你定义了一些模板参数(template<typename T>)未加确定的代码,直到模板被实例化这些参数细节才真正被确定.而非类型模板参数,面对的未加确定的参数细节是指(value),而非类型.当要使用基于值的模板时,你必须显式地指定这些值,模板方可被实例化. 在函数模板中使用非类型参数 #include<iostream> using namesp

  • Symfony实现行为和模板中取得request参数的方法

    本文实例讲述了Symfony实现行为和模板中取得request参数的方法.分享给大家供大家参考,具体如下: 一.模板中取得参数 <?php echo $sf_request->getParameter('name','namespace');?> <?php echo $sf_request->getParameter('name');?> 二.行为中取得参数 $request->getParameter('name'); //模板中取得参数 <?php e

  • Thinkphp模板中使用自定义函数的方法

    注意:自定义函数要放在项目应用目录/common/common.php中. 这里是关键. 模板变量的函数调用格式:{$varname|function1|function2=arg1,arg2,### } 说明: { 和 $ 符号之间不能有空格,后面参数的空格就没有问题: ###表示模板变量本身的参数位置 : 支持多个函数,函数之间支持空格 : 支持函数屏蔽功能,在配置文件中可以配置禁止使用的函数列表 : 支持变量缓存功能,重复变量字串不多次解析. 使用例子: {$webTitle|md5|st

  • 在Django的模板中使用认证数据的方法

    当前登入的用户以及他(她)的权限可以通过 RequestContext 在模板的context中使用. 注意 从技术上来说,只有当你使用了 RequestContext这些变量才可用. 并且TEMPLATE_CONTEXT_PROCESSORS 设置包含了 "django.core.context_processors.auth" (默认情况就是如此)时,这些变量才能在模板context中使用. TEMPLATE_CONTEXT_PROCESSORS 设置包含了 "djang

  • web.py在模板中输出美元符号的方法

    由于web.py已经在模板中定义"$"符号位定界符,所以在模板中如果要使用美元符号需要特殊处理. 如我要在模板中输出"$name"字符串: 复制代码 代码如下: $name 报错 $name被认定为一个变量而不是当作HTML字符串处理.如果想要输出"$name"字符串必须要这么写: 复制代码 代码如下: $$name 保存运行正确输出. 特别是跟jQuery里混合使用的时候,也要注意.如: 复制代码 代码如下: $("id")

  • 在smarty模板中使用PHP函数的方法

    sample1 复制代码 代码如下: <{$colname|trim}> 那如果使用像iconv这样的有三个参数的函数该怎么写呢?如果写成: sample 2 复制代码 代码如下: <{$colname|iconv:'utf-8':'gbk'}> 一执行就会发现显示error信息. 因此研究一下就会发现,起始在smarty模板页的套用函数用法中,以smaple 1来说,trim的前面$Row->colname其实就是trim的第一个参数,中间用|这个符号串接: 那假设要使用像

  • ThinkPHP模板中数组循环实例

    本文实例讲述了ThinkPHP模板中数组循环的实现方法.分享给大家供大家参考.具体实现方法如下: ThinkPHP开发过程中经常用到输出数组在模板中使用,一般select出来的数据都是二维数组,我们在模板中用volist标签就可以输出,今天开发遇到了这样一个问题:如果是二维数组,如何在模板中输出呢?经过查看开发手册,问题得到解决,分享一下,比如这样的一维数组: 复制代码 代码如下: array(2) { [2] => string(12) "www.jb51.net博文配图" [

  • StringUtils工具包中字符串非空判断isNotEmpty和isNotBlank的区别

    在项目中,我们用的最多的是StringUtils中的非空判断方法,相信大部分人都用过IsNotEmpty或者isEmpty方法 今天我们要提到的,是isNotBlank public static boolean isNotEmpty(String str) 判断某字符串是否非空,等于!isEmpty(String str),这里不能排除空格字符 下面是示例: StringUtils.isNotEmpty(null) = false StringUtils.isNotEmpty("")

  • django框架实现模板中获取request 的各种信息示例

    本文实例讲述了django框架实现模板中获取request 的各种信息.分享给大家供大家参考,具体如下: 在做网页程序时,request,response 是少不了的,这是最基本的东西.但 django有自己的框架,在展示层,很少用到直接去取request的内容的.我以前做过java j2ee应用,有时候,经常在jsp页面用request 直接取得想要的内容.即使是用struts,也还是可以用request 去取内容的. 现在在重新用 django 重写一套程序,数据库还是用原来的,有些东西如果

  • ThinkPHP的模版中调用session数据的方法

    ThinkPHP框架的模板中调用session数据的方法有很多,可以很据情况灵活运用,常见的有以下几类: 1.在模板中直接调用{$Think.session}获取session: 2.在<php></php>标签直接编写php代码来调用$_SESSION数据: 3.在模板中写<?php  ?>,然后在里面直接编写php代码来调用$_SESSION: 4.在Action中将$_SESSION变量通过assign()方法赋值给模板: 5.在自定义函数库中,新建一个函数用来返

随机推荐