非类型模板参数

简介: 对于函数模板与类模板,模板参数并不局限于类型,普通值也可以作为模板参数。在基于类型参数的模板中,你定义了一些具体的细节来加以确定代码,直到代码被调用时这些细节才被真正的确定。但是在这里,我们面对的是这些细节是值,而不是类型,当要使用基于值的模板时,必须显式地指定这些值,才能够对模板进行实例化。

对于函数模板与类模板,模板参数并不局限于类型,普通值也可以作为模板参数。在基于类型参数的模板中,你定义了一些具体的细节来加以确定代码,直到代码被调用时这些细节才被真正的确定。但是在这里,我们面对的是这些细节是值,而不是类型,当要使用基于值的模板时,必须显式地指定这些值,才能够对模板进行实例化。

非类型的类模板参数

 

创建类的头文件

#include<stdexcept>
#include<iostream>
using namespace std;

template<typename T, int MAXSIZE>
class Stack{
private:
    T elems[MAXSIZE];
    int numElems;
public:
    Stack();
    void push(T const&);
    void pop();
    T top() const;
    bool empty() const {
        return numElems == 0;
    }
    bool full() const {
        return numElems == MAXSIZE;
    }
};

template<typename T, int MAXSIZE>
Stack<T, MAXSIZE>::Stack():numElems(0) {}

template<typename T, int MAXSIZE>
void Stack<T, MAXSIZE>::push(T const& elem)
{
    if(numElems == MAXSIZE) {
        throw out_of_range("Stack<>::push(): stack is full");
    }
    elems[numElems] = elem;
    ++numElems;
}

template<typename T, int MAXSIZE>
void Stack<T, MAXSIZE>::pop()
{
    if(numElems <= 0) {
        throw out_of_range("Stack<>::pop(): stack is full");
    }
    --numElems;
}

template<typename T, int MAXSIZE>
T Stack<T, MAXSIZE>::top() const
{
    if(numElems <= 0) {
        throw out_of_range("Stack<>::top(): stack is full");
    }
    return elems[numElems - 1];
}

#include<stdexcept>
#include<iostream>
using namespace std;

template<typename T, int MAXSIZE>
class Stack{
private:
    T elems[MAXSIZE];
    int numElems;
public:
    Stack();
    void push(T const&);
    void pop();
    T top() const;
    bool empty() const {
        return numElems == 0;
    }
    bool full() const {
        return numElems == MAXSIZE;
    }
};

template<typename T, int MAXSIZE>
Stack<T, MAXSIZE>::Stack():numElems(0) {}

template<typename T, int MAXSIZE>
void Stack<T, MAXSIZE>::push(T const& elem)
{
    if(numElems == MAXSIZE) {
        throw out_of_range("Stack<>::push(): stack is full");
    }
    elems[numElems] = elem;
    ++numElems;
}

template<typename T, int MAXSIZE>
void Stack<T, MAXSIZE>::pop()
{
    if(numElems <= 0) {
        throw out_of_range("Stack<>::pop(): stack is full");
    }
    --numElems;
}

template<typename T, int MAXSIZE>
T Stack<T, MAXSIZE>::top() const
{
    if(numElems <= 0) {
        throw out_of_range("Stack<>::top(): stack is full");
    }
    return elems[numElems - 1];
}

实现代码:

#include<iostream>
#include<vector>
#include<deque>
#include<stdexcept>
#include<string>
#include<cstdlib>
#include "stack4.h"
using namespace std;


int main()
{
    try {
        Stack<int, 20> int20Stack;
        Stack<int, 40> int40Stack;
        Stack<string, 40> stringStack;
        
        int20Stack.push(7);
        cout<<int20Stack.top()<<endl;
        int20Stack.pop();

        stringStack.push("hello");
        cout<<stringStack.top()<<endl;
        stringStack.pop();
        stringStack.pop();
    }
    catch(exception const& ex) {
        cerr<<"Exception: "<<ex.what()<<endl;
        //return EXIT_FAILURE;
    }
    
    cin.get();  
    return 0;
}

#include<iostream>
#include<vector>
#include<deque>
#include<stdexcept>
#include<string>
#include<cstdlib>
#include "stack4.h"
using namespace std;


int main()
{
    try {
        Stack<int, 20> int20Stack;
        Stack<int, 40> int40Stack;
        Stack<string, 40> stringStack;
        
        int20Stack.push(7);
        cout<<int20Stack.top()<<endl;
        int20Stack.pop();

        stringStack.push("hello");
        cout<<stringStack.top()<<endl;
        stringStack.pop();
        stringStack.pop();
    }
    catch(exception const& ex) {
        cerr<<"Exception: "<<ex.what()<<endl;
        //return EXIT_FAILURE;
    }
    
    cin.get();  
    return 0;
}

MAXSIZE是新加入的第二个模板参数,类型为int,它指定了数组最多可包含的栈元素的个数
同样,我们可以为模板参数指定缺省值:

template<typename T = int, int MAXSIZE = 100>
class Stack {
    ...
};

  非类型的函数模板参数

你也可以为函数模板定义非类型参数。例如:

template<typename T, int VAL>
T addValue(T const& x)
{
    return x + VAL:
}

借助于STL,可以传递这个函数模板的实例化给集中的每一个元素,让他们都增加一个整数值:

std::transform(source.begin(), source.end(), dest.begin(), (int(*)(int const&))addValue<int, 5>);

  非类型模板参数的限制

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

浮点数和类对象是不允许作为非类型模板参数的:

template<double VAT>
double process(double v) //error
{
    return V * VAT;
}

template<string name>  //error
class MyClass {
    ...
};

  另外,你也不能使用全局指针作为模板参数

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

char const* s = "hello";
MyClass<s> x;   //s是一个指向内部连接对象的指针

但是你可以这样使用:

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

extern char const s[] = "hello";
MyClass<s> x;  //OK

全局字符数组s由"hello"初始化,是一个外部链接对象

相关文章
|
Web App开发 域名解析 缓存
如何在 Ubuntu 20.04 上安装 Node.js 和 npm
本文我们主要为大家介绍在 Ubuntu 20.04 上安装 Node.js 和 npm 的三种不同的方式。
161616 7
如何在 Ubuntu 20.04 上安装 Node.js 和 npm
|
开发工具 git 缓存
Git忽略规则.gitignore不生效
在项目开发过程中个,一般都会添加 .gitignore 文件,规则很简单,但有时会发现,规则不生效。 原因是 .gitignore 只能忽略那些原来没有被track的文件,如果某些文件已经被纳入了版本管理中,则修改.gitignore是无效的。
60496 4
|
Ubuntu
vscode配置clang-format自动格式化代码
vscode配置clang-format自动格式化代码
2497 0
vscode 如何修改c/c++格式化风格,大括号不换行
vscode 如何修改c/c++格式化风格,大括号不换行
|
缓存 数据可视化 数据安全/隐私保护
Mac 系统占用100G+解决办法(详细步骤)
Mac 系统占用100G+解决办法(详细步骤)
2773 32
|
机器学习/深度学习 SQL Ubuntu
何时应该考虑使用 WSL 而不是标准 Linux 发行版?
选择标准的 Linux 桌面或 WSL 有时可能会令人困惑。决策取决于您对Linux的需求以及您希望将 Windows 和 Linux 整合到多大程度。 WSL 之所以如此受欢迎,是因为它提供了一种将 Windows 和 Linux 整合在一起的方式,并提供了一些强大的功能。
548 0
|
人工智能 编译器 程序员
C++11之decltype类型推导(使用场景、推导四规则、cv限定符)
C++11之decltype类型推导(使用场景、推导四规则、cv限定符)
568 0
|
数据可视化 Linux 异构计算
如何自动生成设计文件的状态机跳转图(仿真工具使用技巧)【Modesim/Questasim】
如何自动生成设计文件的状态机跳转图(仿真工具使用技巧)【Modesim/Questasim】
如何自动生成设计文件的状态机跳转图(仿真工具使用技巧)【Modesim/Questasim】
|
分布式计算 Java Hadoop
【java】——java项目之逆向工程完结
来到这个公司已经有三个月左右了,一直没有在java方面施展自己的才华,检测自己的容器,终于在大约半个月前,由于公司外包出去的一个java项目需求迭代改动有所繁杂,外包公司衡量该项目无法得到预计收利;最终跟我们公司在合同方面直接谈崩(这只是我了解到的部分原因)。
|
Ubuntu Linux 开发工具
还在用虚拟机吗?通过WSL2在Win10下愉快的玩耍Linux(详细教程+报错解决方案)
还在用虚拟机吗?通过WSL2在Win10下愉快的玩耍Linux(详细教程+报错解决方案)
817 1
还在用虚拟机吗?通过WSL2在Win10下愉快的玩耍Linux(详细教程+报错解决方案)