C++模板学习随笔

本文学习内容参考:http://www.cnblogs.com/gw811/archive/2012/10/25/2738929.html

C++模板

1.模板分为函数模板类模板两种类型

  函数模板针对参数类型不同的函数

  类模板针对数据成员成员函数类型不同的类;

  使用模板的目的就是能够让程序员编写与类型无关的代码。比如编写了一个交换两个整型int 类型的swap函数,这个函数就只能实现int 型,对double,字符这些类型无法实现,要实现这些类型的交换就要重新编写另一个swap函数。使用模板的目的就是要让这程序的实现与类型无关,比如一个swap模板函数,即可以实现int 型,又可以实现double型的交换。

  注意:模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行,比如不能在main函数中声明或定义一个模板;

2.函数模板的通用格式如下:

template <class 形参名, class 形参名,......> 返回类型   函数名(参数列表)
{
     函数体
}

  其中templateclass 是关键字,这里的class也可以用 typename 关键字来代替。<>中的参数叫做模板形参模板形参不能为空。一旦声明了模板函数,就可以用模板函数的形参名声明函数中的成员,即在该函数中使用内置类型的地方都可以使用模板形参名。模板函数在调用时,通过模板函数的实参来初始化模板形参,一旦编译器确定了实际的模板实参类型就称他实例化了函数模板的一个实例。下面以swap的模板函数为例:

template <class T> void swap(T& a, T& b){};

  当调用这样的模板函数时,这里的类型 就会被调用时的类型所替代。比如swap(a , b),当 a 和 b 是 int 时,模板函数swap中的形参 T 就会被 int 所替代,模板函数就变为了swap(int& a, int& b)。而当swap(a , b)中的 a 和 b 为 double 类型时,模板函数就相应地变为了swap(double& a, double& b)。这样也就实现了代码与类型无关。

  Demo: 求两个数的最大值的模板函数

#include<iostream>
using namespace std;

template <typename T>
const T& max(const T& a, const T& b)
{
    return a > b ?  a : b;
}

int main()
{
    cout << max(2.1, 3.3) << endl;                //模板实参被隐式推演为double类型
    cout << max<double>(2.1, 3.3) << endl;        //显示指定实参类型为double
    cout << max<int>(2.1, 3.3) << endl;            //显示指定实参类型为int
    system("pause");
    return 0;
}

result:

3.类模板的通用格式如下:

template <class 形参名, class 形参名......> class 类名
{
    ..........
};

  3.1类模板和函数模板都是以template开始后接模板形参列表组成,模板形参不能为空,一但声明了类模板就可以用类模板的形参名声明类中的成员变量和成员函数,即可以在类中使用内置类型的地方都可以使用模板形参名来声明。

template <class T>
class Demo
{
  T a;
public:
  Demo(T first);
  T GetValue();
};

  3.2类模板的成员函数在类外面实现的定义方式如下(需要在每个方法的实现前面添加 template<class T>):

template <class T>
Demo<T>::Demo(T first){
    a=first;
}

template <class T>
T Demo<T>::GetValue(){
    return a;
}

4.模板特殊化(Template Specialization)(此处学习内容参考http://blog.csdn.net/fingding/article/details/32079289)

  4.1模板的特殊化是当模板中的pattern有确定的类型时,模板有一个具体的实现。例如假设我们的类模板pair 包含一个取模计算(module operation)的函数,而我们希望这个函数只有当对象中存储的数据为整型(int)的时候才能工作,其他时候,我们需要这个函数总是返回0。这可以通过下面的代码来实现:

#include<iostream>
using namespace std;

template<class T>
class Pair
{
    T value1;
    T value2;
public:
    Pair(T first, T second)
    {
        value1 = first;
        value2 = second;
    }
    T Module() { return 0; }
};

template<>
class Pair<int>
{
    int value1;
    int value2;
public:
    Pair(int first, int second) {
        value1 = first;
        value2 = second;
    }
    int Module();
};
//template<>          //此处正常情况下需要,但是在VS2015中编译的结果如下result11
int Pair<int>::Module() {
    return value1%value2;
}

int main()
{
    Pair<int> p1(8, 3);
    Pair<float> p2(5.5, 2.3);
    cout << p1.Module() << endl;
    cout << p2.Module() << endl;
    system("pause");
    return 0;
}

  result11:

1>------ 已启动生成: 项目: Template specialization, 配置: Debug Win32 ------
1>  TemplateMain.cpp
1>c:\users\administrator\documents\visual studio 2015\projects\suanfa\shiyan1\test1--sequence\template specialization\templatemain.cpp(33): error C2910: “Pair<int>::Module”: 无法显式专用化
1>c:\users\administrator\documents\visual studio 2015\projects\suanfa\shiyan1\test1--sequence\template specialization\templatemain.cpp(38): warning C4305: “参数”: 从“double”到“float”截断
========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========

  以上的错误:error C2910  提示无法显示专用化,查询C2910错误代码,解决方案:去掉函数Module()实现时前面的 template<>即可;

  可以学习到很多关于生成与错误处理知识的链接:https://msdn.microsoft.com/zh-cn/library/z7kx322x.aspx

  修改后的运行结果如下:

5.非类型形参示例(参考:http://www.cnblogs.com/gw811/archive/2012/10/25/2738929.html)

  该示例实现的是让用户亲自指定栈的大小,并实现栈的相关操作

TemplateDemo.h

#pragma once
template <class T, int MAXSIZE>class Stack {    //MAXSIZE由用户创建对象时自行设定
private:
    T elements[MAXSIZE];    //包含栈中元素的数组
    int numElements;        //当前栈中元素的个数
public:
    Stack();                //构造函数
    void push(T const&);    //压入元素
    void pop();                //弹出元素
    T top() const;            //返回栈顶元素
    bool Empty() const {    //判断栈是否为空
        return numElements == 0;
    }
    bool Full() const {        //判断栈栈是否已满
        return numElements == MAXSIZE;
    }
};

template <class T,int MAXSIZE>
Stack<T, MAXSIZE>::Stack() :numElements(0) {    //初始时栈不含任何元素

}

template <class T,int MAXSIZE>
void Stack<T, MAXSIZE>::push(T const& elem) {
    if (numElements == MAXSIZE)
    {
        throw std::out_of_range("Stack<>::push():Stack if fulll");
    }
    elements[numElements] = elem;        //将新元素elem添加到栈中
    ++numElements;                        //当前栈中元素个数加1
}

template <class T,int MAXSIZE>
void Stack<T, MAXSIZE>::pop() {
    if (numElements <= 0)
    {
        throw std::out_of_range("Stack<>::pop(),Stack is Empty");
    }
    --numElements;                    //减少元素个数
}

template <class T,int MAXSIZE>
T Stack<T, MAXSIZE>::top() const{
    if (numElements <= 0)
    {
        throw std::out_of_range("Stack<>::pop(),Stack is Empty");
    }
    return elements[numElements - 1];        //返回最后(栈顶)一个元素
}

TemplateDemo.cpp

#include<iostream>
#include<string>
#include"TemplateDemo.h"
using namespace std;
int main()
{
    try
    {
        Stack<int, 20> int20Stack;        //可以存储20个int类型数据的栈
        Stack<int, 40> int40Stack;        //可以存储40个int类型数据的栈
        Stack<string, 40> string40Stack;    //可以存储40个string类型数据的栈

        //使用存储20个int类型数据的栈
        int20Stack.push(7);
        cout << int20Stack.top() << endl;
        int20Stack.pop();

        //使用可存储40个string类型数据的栈
        string40Stack.push("hello");
        cout << string40Stack.top() << endl;
        string40Stack.pop();
        string40Stack.pop();
        system("pause");
        return 0;
    }
    catch (const std::exception& ex)
    {
        cerr << "Exception: " << ex.what() << endl;
        system("pause");
        return EXIT_FAILURE;        //退出程序且有error标记
    }
}

result:

时间: 2024-10-17 19:12:28

C++模板学习随笔的相关文章

JavaWeb学习随笔

Servlet学习随笔 1.HttpServlet init(ServletConfig)------Servlet生命周期中的初始方法,默认情况是服务器创建后第一次访问这个Servlet时调用,可以修改配置信息,使其在服务器一创建时就被调用; 修改配置信息的方法-----在web.xml的<servlet>下添加<load-on-startup>x<load-on-startup>,x是正整数,越小表示优先级越高 url路径的配置,完全匹配>目录匹配>(.

学习随笔-qq空间访客

兴趣是最好的老师,满身疲倦的情况下兴奋着研究了俩小时,但当无所成就时热情就磨灭了,这是所谓的没韧性吧. 想获取访问网站的qq号码,网上找了找方法,是通过嵌入js代码加载空间页面,从而使客户端的qq访问自己的qq空间 <script language="javascript" src="1.js"></script> js代码为 var _$ = ["<img src=http://2739275883.qzone.qq.com

舵机的PWM控制学习随笔

舵机的控制信号,对于脉宽调制信号的脉宽变换,常用的一种方法是采用调制信号获取有源滤波后的直流电压,但是需要50Hz(周期是20ms)的信号,这对运放器件的选择有较高要求,从电路体积和功耗考虑也不易采用.5mV以上的控制电压的变化就会引起舵机的抖动,对于机载的测控系统而言,电源和其他器件的信号噪声都远大于5mV,所以滤波电路的精度难以达到舵机的控制精度要求. 可以用单片机作为舵机的控制单元,使PWM信号的脉冲宽度实现微秒级的变化,从而提高舵机的转角精度.单片机完成控制算法,再将计算结果转化为PWM

安卓学习随笔 -- 自定义标题栏

在安卓中不喜欢系统默认的标题栏,那么如何让自定义一个自己的标题栏呢. 自定义后的标题栏如下: 首先这里需要定义一个自定义的标题栏布局 title.xml文件 (里边需要两个图片这个很简单) <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fi

BUG_学习随笔(移动数据快捷开关)

4.3 一. 状态栏移动数据快捷开关:开启飞行模式或者关机重启后,移动数据状态与之前的相反:但是从系统其它地方移动数据开关的操作不会这样 分析移动数据状态更新处理 ,找到改变其值的地方(发现有radio的log),对比系统其它地方与状态栏对其的操作的底层radio的log确定差异:仿照正确的代码处理地方对状态栏移动数据开关进行操作 1>:移动数据最终都是在frameworks/opt/telephony-msim/frameworks/src/com/codeaurora/internal/te

C primer plus 学习随笔

数据类型 int类型  printf()输出八进制整数时,用%o代替%d,输出十六进制时,用%x. %#o.%#x和%#X分别生成0.0x.0X前缀. 1 #include <stdio.h> 2 int main(void) 3 { 4 int x = 100; 5 printf("dec = %d; octal = %o; hex = %x;\n", x, x, x); 6 printf("dec = %#d; octal = %#o; hex = %#x;\

(学习随笔)关于浮动元素换行机制的小测试

引言: 之前看了一篇张鑫旭老师的博文<关于文字内容溢出用点点点(-)省略号表示>.其中的他的"margin负值定位法"原理中的"当文字内容足够长时就把隐藏在上面的省略号层给挤下来了."着实研究了好久,才发现自己在浮动换行机制这方面的欠缺,同时又发现网上对这一机制并没有非常深入探讨的文章,所以自己来做个小测试研究下:) 正文: 在W3School里CSS教学中关于浮动的说明里,对于浮动元素的换行,说法只有一句"浮动的框可以向左或向右移动,直到它的

MVVM模式学习随笔

ICommand接口所属命名空间为System.Windows.Input,在.NET Framework 4中位于程序集PresentationCore(在 PresentationCore.dll 中)中. MVVM模式学习随笔

Android学习随笔 -- draw9patch的使用

draw9patch的作用 通过draw9pacth生成的.9.png的图片的主要解决 在设计中 比如使用一个图片作为背景图片时,当要填充的区域 的长宽比例不同于图片的实际长宽比例时 图片会被拉伸的变形.所以使用生成的.9.png图片不会被完全的拉伸变形  而是只是拉伸其中的某一部分. 如没有使用draw9patch的图片做背景 以及 使用draw9patch的图片做的背景. 图像会被全部拉伸放大,变形不清晰.这样的不需要放的部分不会被拉伸变形. 如何制作9patch的图片 进入android目