templates(2.1)

Class
Templates

类别模板

就像上一章所说的 functions 那样,classes 也可以针对一或多个类型被参数化。用来管理「各种 不同类型的元素」的
container classes(容器类别)就是典型例子。运用 class templates 你可以实 作出可包容各种类型的 container
class。本章将以一个 stack class 作为 class templates


/* The following code example is taken from the book
* "C++ Templates - The Complete Guide"
* by David Vandevoorde and Nicolai M. Josuttis, Addison-Wesley, 2002
*
* (C) Copyright David Vandevoorde and Nicolai M. Josuttis 2002.
* Permission to copy, use, modify, sell and distribute this software
* is granted provided this copyright notice appears in all copies.
* This software is provided "as is" without express or implied
* warranty, and with no claim as to its suitability for any purpose.
*/
#include <vector>
#include <stdexcept>

template <typename T>
class Stack {
private:
std::vector<T> elems; // elements

public:
void push(T const&); // push element
void pop(); // pop element
T top() const; // return top element
bool empty() const { // return whether the stack is empty
return elems.empty();
}
};

template <typename T>
void Stack<T>::push (T const& elem)
{
elems.push_back(elem); // append copy of passed elem
}

template<typename T>
void Stack<T>::pop ()
{
if (elems.empty()) {
throw std::out_of_range("Stack<>::pop(): empty stack");
}
elems.pop_back(); // remove last element
}

template <typename T>
T Stack<T>::top () const
{
if (elems.empty()) {
throw std::out_of_range("Stack<>::top(): empty stack");
}
return elems.back(); // return copy of last element
}

正如你所见,这个 class template 是以标准库的 class template vector<>
为基础实作出来的, 这样我们就可以不考虑内存管理、copy构造函数、assignment 运算符等等,从而得以把注意力放在这个 class template
的界面上。

3.1.1
Class Templates 的声明

声明class templates 的动作和声明function templates
类似:在声明语句之前加一条述句,以任意标识符声明类型参数(type parameters)。我们还是以T 作为标识符:


template <typename T>
class Stack {
  ...
};

相同的规则再次适用:关键词 class
可以代替关键词 typename


template <class T>
class Stack {
  ...
};

在 class template 内部,T
就像其它任意类型一样,可用来声明成员变量(member variables)和成员函数(member functions)。本例之中T
用来声明vector<> 所容纳的元素类型、声明一个「接受 T const&」的 push()函数、以及声明一个「返回类型为 T」的
top()函数:


template <typename T>
class Stack {
private:
  std::vector<T> elems; // 元素
public:
  Stack(); // 构造函数
void push(T const&); // push 元素
void pop(); // pop 元素
T top() const; // 传回最顶端的元素
};

这个 class 的类型为 Stack<T>,T 是一个 template
parameter。现在,无论何时你以这个class声明变量或函数时,都应该写成 Stack<T>。例如,假设你要声明自己的 copy
构造函数和assignment 运算符,可以写为:


template <typename T>
class Stack {
...
Stack (Stack<T> const&); // copy 构造函数
Stack<T>& operator= (Stack<T> const&); // assignment 运算符
...
};

然而如果只是需要class名称而不是class类型时,只需写Stack
即可。构造函数和析构函数的声明就属于这种情况。

3.1.2
成员函数( Member Functions)

作为了定义 class template 的成员函数,你必须指出它是个 function template,而且你必须使用
class template 的全称。因此 Stack<T> 的成员函数 push()看起来便像这样:


template <typename T>
void Stack<T>::push (T const& elem)
{
  elems.push_back(elem); // 将传入的元素 elem 附加于尾
}

这里调用了vector 的成员函数push_back(),把元素elem 追加到elems
尾端。注意,对一个vector进行 pop_back(),只是把最后一个元素移除,并不传回该元素。这种行为乃是基于异常安全性(exception
safety)考虑。实现一个「移除最后元素并传回,而且完全顾及异常安全性」的 pop() 是不可能的( 这个问题最早由 Tom Cargill
在[CargillExceptionSafety]中 讨论过),[SutterExceptional] 条款 10
也有讨论)。然而,如果抛开可能的危险,我们可以实作出一个「移除最后元素并传回」的pop(),但必须声明一个类型为 T 的区域变量:


template <typename T>
T Stack<T>::pop ()
{
if (elems.empty()) {
throw std::out_of_range("Stack<>::pop: empty stack");
}
T elem = elems.back(); // 保存最后元素的拷贝
elems.pop_back(); // 移除最后一个元素
return elem; // 传回先前保存的最后元素
}

当vector为空时,对它进行back()或pop_back()操作会导致未定义行为。所以我们必须在操作前先检查stack是否为空。如果stack为空,就抛出一个std::out_of_range
异常。top()之中也需进行相同检查;该函数传回 stack 的最后一个元素,但不移除之:


template <typename T>
T Stack<T>::top () const
{
if (elems.empty()) {
throw std::out_of_range("Stack<>::top: empty stack");
}
return elems.back(); // 传回最后元素的拷贝
}

当然,你也可以把任何 class templates 的成员函数实作码写在 class
声明语句中,形成一个 inline函式。例如:


template <typename T>
class Stack {
...
void push(T const& elem) {
elems.push_back(elem); // 将传入的元素 elem 附加于尾
}
...
};

3.2
使用 Class Template Stack


/* The following code example is taken from the book
* "C++ Templates - The Complete Guide"
* by David Vandevoorde and Nicolai M. Josuttis, Addison-Wesley, 2002
*
* (C) Copyright David Vandevoorde and Nicolai M. Josuttis 2002.
* Permission to copy, use, modify, sell and distribute this software
* is granted provided this copyright notice appears in all copies.
* This software is provided "as is" without express or implied
* warranty, and with no claim as to its suitability for any purpose.
*/
#include <iostream>
#include <string>
#include <cstdlib>
#include "stack1.hpp"

int main()
{
try {
Stack<int> intStack; // stack of ints
Stack<std::string> stringStack; // stack of strings

// manipulate int stack
intStack.push(7);
std::cout << intStack.top() << std::endl;

// manipulate string stack
stringStack.push("hello");
std::cout << stringStack.top() << std::endl;
stringStack.pop();
stringStack.pop();
}
catch (std::exception const& ex) {
std::cerr << "Exception: " << ex.what() << std::endl;
return EXIT_FAILURE; // exit program with ERROR status
}
}

上例声明了 Stack<int>这样一个类型,表示在该 class template 中 T 被替换为 int。于是
intStack成为这样一个object:内部使用「可容纳int 数据做为元素」的vector,并将被调用之任何成员函数都「以int
类型进行实例化」。同样道理,Stack<std::string> 表示:stringStack
被创建为这样一个object:内部使用「可容纳string 数据做为元素」的vector,并将被调用之任何成员函数都「以std::string
类型进行实例化」。

注意,惟有被调用到的成员函数,才会被实例化(instantiated)。对class templates
而言,只有当某个成员函数被使用时,才会进行实例化。无疑地这么做可以节省时间和空间。另一个好处是,你甚至可以实例化一个class
template,而具现类型并不需要完整支持「class template 内与该
类型有关的所有操作」—前提是那些操作并未真正被叫用。举个例子,考虑某个class,其某些成员函数使用operator<
对内部元素排序;只要避免调用这些函数,就可以以一个「并不支持 operator<」的类型来实例化这个 class template。

本例中的 default 构造函数、push()函数和 top()函数都同时被 int 和 string
类型加以实现(实例化)。然而 pop()只被 string 实例化(译注:因为 pop()只被 stringStack 调用)。如果 class
template 拥有 static 成员,这些 static 成员会针对每一种被使用的类型完成实例化。

你可以像面对任何基本类型一样地使用一个实例化后的class template类型,前提是你的使用方式合法:


void foo (Stack<int> const& s) // 参数 s 是一个 int stack
{
Stack<int> istack[10]; // istack 是一个「含有 10 个 int stacks」的 array
...
}

运用 typedef,你可以更方便地使用 class
templates:


typedef Stack<int> IntStack;
void foo (IntStack const& s) // 参数 s 是一个 int stack
{
IntStack istack[10]; // istack 是一个「含有 10 个 int stacks」的 array
...
}

注意,在C++中,typedef 并不产生新类型,只是为既有类型产生一个别名(type
alias)。因此


typedef Stack<int> IntStack;

IntStack 和 Stack<int>拥有(代表)相同类型,可以互换使用,可以相互赋值(assigned)。

Template arguments 可以是任意类型,例如可以是「指向 float」的指针,或甚至是个 int stack:

Stack<float*> floatPtrStack; // stack of float

pointers Stack<Stack<int> > intStackStack; // stack of stack of ints 惟一的条件是:该类型必须支持所有「实际被调用到的操作」。

注意,你必须在相邻两个右角括号之间插入一些空白符号(像上面那样),否则就等于使用了

operator>>,那会导致语法错误:

Stack<Stack<int>> intStackStack; // 错误:此处不允许使用 >>

在以下述句之后:

templates(2.1)

时间: 2024-07-31 13:54:54

templates(2.1)的相关文章

Django的第一个Templates

1.URL配置方法: myblog中的urls.py 的文件 from django.conf.urls import url,include from django.contrib import admin import blog.views as bv urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^$', include('blog.urls')), ] blog中创建一个urls.py文件 from django.conf

springboot 1.5.2 thymeleaf 添加templates 静态资源访问路径

从velocity 模板切换到thymeleaf 后, 默认模板位置为templates , 有时候静态资源方在该目录下会出现访问404错误 解决办法: application.properties 中添加: spring.mvc.static-path-pattern=/** spring.resources.static-locations=classpath:/templates/,classpath:/META-INF/resources/,classpath:/resources/,c

[Ember] Ember.js Templates

In this lesson, we'll go over some of the basics of Ember.js templates and how they work with controllers. Generate a controller: ember g controller hello Generate a Template: ember g template application Template syntax: application.hbs: {{#if showN

warning: templates not found

在 Mac上用 SourceTree 克隆代码的时候, 出现了 warning: templates not found /user/local/git/share/git-core/templates 警告,导致克隆失败 在终端输入 sudo mkdir /usr/local/git sudo mkdir /usr/local/git/share sudo mkdir /usr/local/git/share/git-core sudo mkdir /usr/local/git/share/g

free CSS and HTML5 site templates

http://templated.co/ 模板 A collection of 850 free CSS and HTML5 site templates, designed & built by Cherry + AJ and released under the Creative Commons https://tampermonkey.net/ Tampermonkey : Tampermonkey is a free browser extension and the most popu

【Silverlight】Templates的用法

<Button Content="A Custom Button Template" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="174,120,0,0"> <Button.Template> <ControlTemplate TargetType="Button" > <Border Bor

格式工厂(三) Variadic Templates

版权声明:本文为博主原创文章,未经博主允许不得转载. 这次主要介绍C++11的又一个新特性 Variadic Templates (可变模板参数) 它的实现类似于initializer_list<>,它可是使类模板接受一包参数 本节主要应用递归的形式介绍 Variadic  Templates 1.简单的调用 #include <iostream> #include "string" using namespace std; void printX() {}//

Django Templates

二分春色到穷阎,儿女祈翁出滞淹.幽蛰夜惊雷奋地,小窗朝爽日筛帘. 惠风全解墨池冻,清昼胜翻云笈签.亲友莫嗔情话少,向来屏息似龟蟾. 料峭寒犹薄,阴云带晚烟. 雨催惊蛰候,风作勒花开. 日永消香篆,愁浓逼酒船. 为君借余景,收拾赋新篇. 作者:小亲姐姐来源链接:http://www.qbaobei.com/jiaoyu/407464.html来源:亲亲宝贝著作权归作者所有. 料峭寒犹薄,阴云带晚烟. 雨催惊蛰候,风作勒花开. 日永消香篆,愁浓逼酒船. 为君借余景,收拾赋新篇. 作者:小亲姐姐来源链

C++模板(Templates)

模板(template)是泛型编程的基础,"泛型"的含义就是没有不依赖具体的数据类型.模板的引入是为了创建一般性的类(模板类)或者函数(模板函数).典型的容器比如迭代器/算法等是泛型编程的典型案例.例如,定义了一个vector,可以使用vector<int>, vector<string>, vector<vector>等等. 函数模板 模板函数的一般定义方式为: 这里的type可以看做是代表了一种数据类型的占位符名称, 在函数内部的定义中可以使用它

django复习笔记3:urls/views/templates三板斧

0.先看看文件结构 sh-3.2# tree -L 2 mysite/ mysite/ ├── __pycache__ │   └── manage.cpython-34.pyc ├── blog │   ├── __init__.py │   ├── __init__.pyc │   ├── __pycache__ │   ├── admin.py │   ├── admin.pyc │   ├── migrations │   ├── models.py │   ├── models.pyc