1. 定义类模板
程序清单类模板-1列出了类模板和成员函数模板,明确这些模板不是类和成员函数定义很重要,因为它们是C++编译指令,说明了如何生成类和成员函数定义。
不能将模板成员函数放在独立的实现文件中,由于模板不是函数,它们不能单独编译,模板必须与特定的模板实例化请求一起使用。因此,最简单的方式是将所有模板信息放在一个头文件中,并再要使用这些模板的文件中包含该头文件。
//程序清单 类模板-1
//stacktp.h
#ifndef STACKTP_H_
#define STACKTP_H_
template<class Type>
class Stack
{
private:
enum {MAX = 10}; //Stack类拥有的常量
Type items[MAX];
int top;
public:
Stack();
bool isempty();
bool isfull();
bool push(const Type& item); //add item to stack
bool pop(Type& item); //pop top into item
};
template<class Type>
Stack<Type>::Stack()
{
top = 0;
}
template<class Type>
bool Stack<Type>::isempty()
{
return top == 0;
}
template<class Type>
bool Stack<Type>::isfull()
{
return top == MAX;
}
template<class Type>
bool Stack<Type>::push(const Type& item)
{
if(top < MAX)
{
items[top++] = item;
return true;
}
else
return false;
}
template<class Type>
bool Stack<Type>::pop(Type& item)
{
if(top > 0)
{
item = items[--top];
return true;
}
else
return false;
}
#endif
注意模板成员函数定义与类模板声明一起放在模板的头文件中。
2. 使用模板类
仅在程序中包含模板并不能生成模板类,必须请求实例化,必须显式地提供所需的类型。
Stack<int> kernels;
Stack<std::string> colonels;
3. 深入探讨模板类
正确使用指针栈的方法之一是,让调用程序提供一个指针数组,其中每个指针都指向不同的字符串。注意,栈的任务是管理指针,不是创建指针。程序清单类模板-2重新定义了Stack<Type>类,使Stack构造函数能够接受一个可选大小的参数。这涉及到在内部使用动态数组,因此Stack类需要包含一个析构函数、一个复制构造函数和一个赋值运算符。
//程序清单 类模板-2
//stcktp1.h
#ifndef STCKTP1_H_
#define STCKTP1_H_
template<class Type>
class Stack
{
private:
enum {SIZE = 10}; //默认大小
int stacksize;
Type* items;
int top;
public:
explicit Stack(int ss = SIZE);
Stack(const Stack& st);
~Stack() { delete[] items; }
bool isempty() { return top == 0; }
bool isfull() { return top == stacksize; }
bool push(const Type& item);
bool pop(Type& item);
Stack& operator=(const Stack& st);
};
template<class Type>
Stack<Type>::Stack(int ss): stacksize(ss), top(0)
{
item = new Type[stacksize];
}
template<class Type>
Stack<Type>::Stack(const Stack<Type>& st)
{
stacksize = st.stacksize;
top = st.top;
items = new Type[stacksize];
for(int i = 0; i < top; i++)
{
items[i] = st.items[i];
}
}
template<class Type>
bool Stack<Type>::push(const Type& item)
{
if(top < stacksize)
{
items[top++] = item;
return true;
}
return false;
}
template<class Type>
bool Stack<Type>::pop(Type& item)
{
if(top > 0)
{
item = items[--top];
return true;
}
return false;
}
template<class Type>
Stack<Type>& Stack<Type>::operator=(const Stack<Type>& st)
{
if(this == &st)
return *this;
delete[] items;
stacksize = st.stacksize;
top = st.top;
items = new Type[stacksize];
for(int i = 0; i < top; i++)
{
items[i] = st.items[i];
}
return *this;
}
#endif
程序清单类模板-3使用了这个Stack模板类。
//程序清单 类模板-3
//stkoptr1.cpp
#include <iostream>
#include <cstdlib>
#include <ctime>
#include "stcktp1.h"
const int Num = 10;
int main()
{
std::srand(std::time(0));
std::cout << "Please enter stack size: ";
int stacksize;
std::cin >> stacksize;
//create an empty stack with stacksize siots
Stack<const char*> st(stacksize);
//in basket
const char* in[Num] = {
" 1: Hank Gilgamesh", " 2: Kiki Ishtar",
" 3: Betty Rocker", " 4: Ian Flagranti",
" 5: Wolfgang Kibble", " 6: Portia Koop",
" 7: Joy Almondo", " 8: Xaverie Paprika",
" 9: Juan Moore", " 10: Misha Mache"
};
//out basket
const char* out[Num]; //类型为const char*,因为指针数组被初始化为一组字符串常量
int processed = 0;
int nextin = 0;
while(processed < Num)
{
if(st.isempty())
st.push(in[nextin++]);
else if(st.isfull())
st.pop(out[processed++]);
else if(std::rand() % 2 && nextin < Num)
st.push(in[nextin++]);
else
st.pop(out[processed++]);
}
for(int i = 0; i < Num; i++)
{
std::cout << out[i] << std::endl;
}
std::cout << "Bye\n";
return 0;
}
4. 数组模板示例和非类型参数
模板常用作容器类。
自己设计一个允许指定数组大小的简单数组模板。一种方法是在类中使用动态数组和构造函数参数来提供元素数目,例如程序清单类模板-2;另一种方法是使用模板参数来提供常规数组的大小,C++11新增的模板array就是这样做的,程序清单类模板-4演示了如何做。
//程序清单 类模板-4
//arraytp.h
#ifndef ARRAYTP_H_
#define ARRAYTP_H_
#include <iostream>
#include <cstdlib>
template<class T, int n>
class ArrayTP
{
private:
T ar[n];
public:
ArrayTP() {};
explicit ArrayTP(const T& v);
virtual T& operator[] (int i);
virtual T operator[](int i) const;
};
template<class T, int n>
ArrayTP<T, n>::ArrayTP(const T& v)
{
for(int i = 0; i < n; i++)
ar[i] = v;
}
template<class T, int n>
T& ArrayTP<T, n>::operator[](int i)
{
if(i < 0 || i >= n)
{
std::cerr << "Error in array limits: " << i << " is out of range\n";
std::exit(EXIT_FAILURE);
}
return ar[i];
}
template<class T, int n>
T ArrayTP<T, n>::operator[](int i) const
{
if(i < 0 || i >= n)
{
std::cerr << "Error in array limits: " << i << " is out of range\n";
std::exit(EXIT_FAILURE);
}
return ar[i];
}
#endif
关键字class指出T为类型参数,int指出n的类型为int。这种参数(指定特殊的类型而不是用作泛型名)称为非类型(non-type)或表达式(expression)参数。
表达式参数有一些限制,表达式参数可以是整形、枚举、引用或指针。因此double m是不合法的,但double& rm和double* pm是合法的。另外,模板代码不能改变参数的值,也不能使用参数的地址。所以在ArrayTP模板中不能使用诸如n++和&n等表达式。另外,实例化模板时,用作表达式参数的值必须是常量表达式。
5. 模板的多功能性
可以将用于常规类的技术用于模板类。模板类可以用作基类,也可用作组件类,还可用作其他模板的类型参数。例如,可以使用数组模板实现栈模板,也可以使用数组模板来构造数组——数组元素是基于栈模板的栈。即可以编写如下代码:
template<typename T>
class Array
{
private:
T entry;
//...
};
template<typename Type>
class GrowArray: public Array<Type>
{
//... //inheritance
}
template<typename Tp>
class Stack
{
Array<Tp> ar; //use an Array<> as a component
}
//...
Array< Stack<int> > assi; // an array of stacks of int
5.1 递归使用模板
可以递归使用模板,例如对于前面的数组模板定义,可以这样使用它:
ArrayTP< ArrayTP<int, 5>, 10> twodee;
与之等价的常规数组声明如下:
int twodee[10][5]
5.2 使用多个类型参数
模板可以包含多个类型参数。例如,假设希望类可以保存两种值,则可以创建并使用Pair模板来保存两个不同的值(标准模板库提供了类似的模板,名为pair)。程序清单类模板-5所示的小程序是一个这样的示例。其中,方法first() const和second() const报告存储的值。由于这两个方法返回Pair数据成员的引用,因此可以通过赋值重新设置存储的值。
//程序清单 类模板-5
//pairs.cpp -- defining and using a Pair template
#include <iostream>
#include <string>
template<class T1, class T2>
class Pair
{
private:
T1 a;
T2 b;
public:
T1& first();
T2& second();
T1 first() const { return a; }
T2 second() const { return b; }
Pair(const T1& aval, const T2& bval): a(aval), b(bval) {}
Pair() {}
};
template<class T1, class T2>
T1& Pair<T1, T2>::first()
{
return a;
}
template<class T1, class T2>
T2& Pair<T1, T2>::second()
{
return b;
}
int main()
{
using std::cout;
using std::endl;
using std::string;
Pair<string, int> ratings[4] =
{
Pair<string, int>("The Purpled Duck", 5),
Pair<string, int>("Jaquie's Frisco Al Fresco", 4),
Pair<string, int>("Cafe Souffle", 5),
Pair<string, int>("Bertie's Eats", 3)
};
int joints = sizeof(ratings) / sizeof(Pair<string, int>); //必须用Pair<string, int>来调用构造函数,并将它作为sizeof的参数,因为类名是Pair<string, int>,而不是Pair
cout << "Rating:\t Batery\n";
for(int i = 0; i < joins; i++)
cout << ratings[i].second() << ":\t"
<< ratings[i].first() << endl;
cout << "Oops! Revised rating:\n";
ratings[3].first() = "Bertie's Fab Eats";
ratings[3].second() = 6;
cout << rating[3].second() << ":\t "
<< ratings[3].first() << endl;
return 0;
}
5.3 默认类型模板参数
类模板的另一项新特性是,可以为类型参数提供默认值:
template<class T1, class T2 = int>
class Topo
{
//...
};
这样,如果省略了T2的值,编译器将使用int。标准模板库经常使用该特性,将默认类型设置为类。虽然可以为类模板类型参数提供默认值,但不能为函数模板参数提供默认值。然而,可以为非类型参数提供默认值,这对于类模板和函数模板都是适用的。
6. 模板的具体化
类模板与函数模板很相似,因为可以有隐式实例化、显式实例化和显式具体化。它们统称为具体化(specialization)。模板以泛型的方式描述类,而具体化是使用具体的类型生成类声明。
6.1 隐式实例化
目前为止,本文章所有的模板示例使用的都是隐式实例化,即它们声明一个或多个对象,指出所需的类型,而编译器使用通用模板提供的说明生成具体的类定义。
ArrayTP<int, 100> stuff; //implicit instantiation
编译器在需要对象之前,不会生成类的隐式实例化:
ArrayTP<double, 30> *pt; //仅声明一个指针,不需要实际对象
pt = new ArrayTP<double, 30>; //现在需要一个实际对象
第二条语句导致编译器生成类定义,并根据该定义创建一个对象。
6.2 显式实例化
当使用关键字template并指出所需类型来声明类时,编译器将生成类声明的显式实例化。声明必须位于模板定义所在的名称空间中。
template class ArrayTP<string, 100>;
此时,虽然没有创建类对象,编译器也将生成类声明(包括方法定义)。和隐式实例化一样,也将根据通用模板来生成具体化。
6.3 显式具体化
显式具体化是特定类型(用于替换模板中的泛型)的定义。有时候,可能需要在为特殊类型实例化时,对模板进行修改,使其行为不同。此时可以创建显式具体化。例如,假设已经为用于表示排序后数组的类(元素在加入时被排序)定义了一个模板:
template <typename T>
class SortedArray
{
//details omitted
};
另外,假设模板使用>运算符来对值进行比较。对于数字,这样管用。如果T表示一种类,则只要定义了T::operator>()方法,这也管用。但如果T是const char*字符串,将不管用。如果强行使用此模板,则字符串将按地址(按照字母顺序)排序。这要求类定义使用strcmp(),而不是>来对值进行比较。此时可以提供一个显式模板具体化,这将采用为具体类型定义的模板,而不是为泛型定义的模板。当具体化模板和通用模板都与实例化请求匹配时,编译器将使用具体化版本。
具体化类模板定义的格式:
template <> class SortedArray<const char*>
{
// details omitted
};
其中的实现代码将使用strcmp()(而不是>)来比较数组值。现在,当请求const char*类型的SortedArray模板时,编译器将使用上述专用的定义,而不是通用的模板定义。
6.4 部分具体化
C++还允许部分具体化(partial specialization),即部分限制模板的通用性。
//模板声明
template<class T1, class T2> class Pair
{
};
//部分具体化:将T2限制为int
template<class T1> class Pair<T1, int>
{
};
注意,如果指定所有的类型,则<>内将为空,这将导致显示具体化:
// specialization with T1 and T2 set to int
template<> class Pair<int, int>
{
};
也可以通过为指针提供特殊版本来部分具体化现有的模板:
template<class T>
class Feeb
{
};
template<class T*>
class Feeb
{
};
7. 成员模板
模板可用作结构、类或模板类的成员。要完全实现STL的设计,必须使用这项特性。
// 程序清单 类模板-6
// 该程序清单提供一个简单的模板类示例,该模板类将另一个模板类和模板函数作为其成员
// tempmemb.cpp -- template members
#include <iostream>
using std::cout;
using std::endl;
template<typename T>
class beta
{
private:
template<typename V>
class hold
{
private:
V val;
public:
hold(V v = 0): val(v) {}
void show() const { cout << val << endl; }
V Value() const { return val; }
};
hold<T> q; // template object
hold<int> n; // template object
public:
beta(T t, int i): q(t), n(i) {}
template<typename U>
U blab(U u, T t) { return (n.Value() + q.Value()) * u / t; }
void Show() const { q.show(); n.show(); }
};
int main()
{
beta<double> guy(3.5, 3);
cout << "T was set to double\n";
guy.Show();
cout << "V was set to T, which is double, then V was set to int\n";
cout << guy.blab(10, 2.3) << endl;
cout << "U was set to int\n";
cout << guy.blab(10.0, 2.3) << endl;
cout << "U was set to double\n";
cout << "Done\n";
return 0;
}
注意:blab()方法的U类型由该方法被调用时的参数值显式确定,T类型由对象的实例化类型确定。在这个例子中,guy的声明将T的类型设置为double,而下述方法调用的第一个参数将U的类型设置为int(参数10对于的类型):
cout << guy.blab(10, 2.5) << endl;
因此,虽然混合类型引起的自动类型转换导致blab()中的计算以double类型进行,但返回值的类型为U(即int),因此它被截断为28。
可以在beta模板中声明hold类和blab方法,并在beta模板的外面定义它们。如果所用的编译器接受类外面的定义,则在beta模板之外定义模板方法的代码如下:
template<typename T>
class beta
{
private:
template<typename V> class hold;
hold<T> q;
hold<int> n;
public:
beta(T t, int i): q(t), n(i) {}
template<typename U>
U blab(U u, T t);
void Show() const { q.show(); n.show(); }
};
//成员定义
template<typename T>
template<typename V>
class beta<T>::hold
{
private:
V val;
public:
hold(V v = 0): val(v) {}
void show() const { std::cout << val << std::endl(); }
V Value() const { return val; }
};
template<typename T>
template<typename U>
U beta<T>::blab(U u, T t)
{
return (n.Value() + q.Value()) * u / t;
}
因为模板是嵌套的,必须使用下面的语法:
template<typename T>
template<typename V>
定义还必须指出hold和blab是beta<T>类的成员。这是通过使用作用域解析运算符来完成的。
8. 将模板用作参数
模板可以包含类型参数(如typename T)和非类型参数(如int n)。模板还可以包含本身就是模板的参数,这种参数是模板新增的特性,用于实现STL。
// 程序清单 - 类模板-7 将模板用作参数
// tempparm.cpp - templates as parameters
#include <iostream>
#include "stacktp.h"
template<template<typename T> class Thing>
class Crab
{
private:
Thing<int> s1;
Thing<double> s2;
public:
Crab() {}
// assumes the Thing class has push() and pop() members
bool push(int a, double x) { return s1.push(a) && s2.push(x); }
bool pop(int& a, double& x) { return s1.pop(a) && s2.pop(x); }
};
int main()
{
using std::cout;
using std::cin;
using std::endl;
Crab<Stack> nebula;
// Stack class must match template<typename T> class Thing
int ni;
double nb;
cout << "Enter int double pairs, such as 4 3.5 (0 0 to end):\n";
while(cin >> ni >> nb && ni > 0 && nb > 0)
{
if(!nebula.push(ni, nb))
break;
}
while(nebula.pop(ni, nb))
cout << ni << ", " << nb << endl;
cout << "Done.\n";
return 0;
}
可以混合使用模板参数和常规参数,例如,Crab类的声明可以像下面这样打头:
template<template<typename T> class Thing, typename U, typename V>
class Crab
{
private:
Thing<U> s1;
Thing<V> s2;
// ...
};
现在,成员s1和s2可存储的数据类型为泛型,而不是用硬编码指定的类型。
9. 模板类和友元
模板类声明也可以有友元。模板的友元分为3类:
- 非模板友元;
- 约束(bound)模板友元,即友元的类型取决于类被实例化时的类型;
- 非约束(unbound)模板友元,即友元的所有具体化都是类的每一个具体化的友元。
9.1 模板类的非模板友元函数
在模板类中将一个常规函数声明为友元:
template<class T>
class HasFriend
{
public:
friend void counts();
};
上述声明使counts()函数成为模板所有实例化的友元。例如,它将是类hasFriend<int>和hasFriend<string>的友元。
counts()函数不是通过对象调用的(它是友元,不是成员函数),也没有对象参数,那么它如何访问HasFriend对象呢?有很多种可能性。它可以访问全局对象;可以使用全局指针访问非全局对象;可以创建自己的对象;可以访问独立于对象的模板类的静态数据成员。
假设要为友元函数提供模板类参数,可以如下所示来进行友元声明吗?
friend void report(HasFriend&); //impossible
答案是不可以,原因是不存在HasFriend这样的对象,而只有特定的具体化,如HasFriend<short>。要提供模板类参数,必须指明具体化。例如:
template<class T>
class HasFriend
{
friend void report(HasFriend<T>&); //bound template friend
}
上述代码示例,带HasFriend<int>参数的report()将成为HasFriend<int>类的友元。同样,带HasFriend<double>参数的report()将是report()的一个重载版本——它是HasFriend<double>类的友元。注意,report()本身并不是模板函数,而只是使用一个模板作参数。这意味着必须为要使用的友元定义显式具体化:
void report(HasFriend<short>&) { };
void report(HasFriend<int>&) { };
//程序清单 - 类模板-8 非模板友元
//frnd2tmp.cpp -- template class with non-template friends
#include <iostream>
using std::cout;
using std::endl;
template<typename T>
class HasFriend
{
private:
T item;
static int ct;
public:
HasFriend(const T& i): item(i) { ct++; }
~HasFriend() { ct--; }
friend void counts();
friend void reports(HasFriend<T>&); //模板作参数
};
// each specialization has its own static data member
template<typename T>
int HasFriend<T>::ct = 0;
// non template friend to all HasFriend<T> classes
void counts()
{
cout << "int count: " << HasFriend<int>::ct << "; ";
cout << "double count: " << HasFriend<double>::ct << endl;
}
// non template friend to the HasFriend<int> class
void report(HasFriend<int>& hf)
{
cout << "HasFriend<int>: " << hf.item << endl;
}
// non template friend to the HasFriend<double> class
void reports(HasFriend<double>& hf)
{
cout << "HasFriend<double>: " << hf.item << endl;
}
int main()
{
// ...
}
程序清单类模板-8中,HasFriend模板有一个静态成员ct。这意味着这个类的每一个特定的具体化都将有自己的静态成员。count()方法是所有HasFriend具体化的友元,它报告两个特定的具体化(HasFriend<int>和HasFriend<double>)的ct的值。该程序还提供两个report()函数,它们分别是某个特定HasFriend具体化的友元。
9.2 模板类的约束模板友元函数
可以修改前一个示例,使友元函数本身成为模板。具体地说,为约束模板友元作准备,要使类的每一个具体化都获得与友元匹配的具体化。这比非模板友元复杂些,包含以下三步:
首先,在类定义的前面声明每个模板函数。
template <typename T> void counts();
template <typename T> void report(T&);
然后,在模板类中再次将模板函数声明为友元。这些语句根据类模板参数的类型声明具体化:
template <typename TT>
class HasFriendT
{
//...
friend void counts<TT>();
friend void report<>(HasFriendT<TT>&);
};
声明中的<>指出这是模板具体化。对于report(),<>可以为空,因为可以从函数参数推断出如下模板类型参数:HasFriend<TT>。也可以使用:
report<HasFriendT<TT> >(HasFriendT<TT>&);
但counts()函数没有参数,因此必须使用模板参数语法(<TT>)来指明具体化。需要注意,TT是HasFriendT类的参数类型。
理解这些声明的最佳方式是设想声明一个特定具体化的对象时,它们将变成什么样。例如,假设声明了这样一个对象:
HasFriendT<int> squack;
编译器将用int替换TT,并生成下面的类定义:
class HasFriendT<int>
{
//...
friend void counts<int>();
friend void report<>(HasFriendT<int>&);
};
程序清单类模板-9说明了上述知识点,注意类模板-8包含1个counts()函数,它是所有HasFriend类的友元;而类模板-9包含2个counts()函数,它们分别是某个被实例化的类类型的友元。因为counts()函数调用没有可被编译器用来推断出所需具体化的函数参数,所以这些调用使用counts<int>和counts<double>指明具体化。但对于report()调用,编译器可以从参数类型推断出要使用的具体化。使用<>格式也能获得同样的效果:
report<HasFriendT<int> >(hfi2);
// 类模板-9
// tmp2tmp.cpp -- template friends to a template class
#include <iostream>
using std::cout;
using std::endl;
//template prototypes
template<typename T> void counts();
template<typename T> void report(T&);
//template class
template<typename TT>
class HasFriendT
{
private:
TT item;
static int ct;
public:
HasFriendT(const TT& i): item(i) { ct++; }
~HasFriendT() { ct--; }
friend void counts<TT>();
friend void report<>(HasFriendT<TT>&);
};
template<typename T>
int HasFriendT<T>::ct = 0;
//template friend functions definitions
template<typename T>
void counts()
{
cout << "template size: " << sizeof(HasFriendT<T>) << "; ";
cout << "template counts(): " << HasFriendT<T>::ct << endl;
}
template<typename T>
void report(T& hf)
{
cout << hf.item << endl;
}
int main()
{
counts<int>();
HasFriendT<int> hfi1(10);
HasFriendT<int> hfi2(20);
HasFriend<double> hfdb(10.5);
report(hfi1); //generate report(HasFriendT<int>&)
report(hfi2);
report(hfdb);
cout << "counts<int>() output:\n";
counts<int>();
cout << "counts<double>() output:\n";
counts<double>();
return 0;
}
9.3 模板类的非约束模板友元函数
前一节中的约束模板友元函数是在类外面声明的模板的具体化。int类具体化获得int函数具体化,以此类推。通过在类内部声明模板,可以创建非约束友元函数,即每个函数具体化都是每个类具体化的友元。对于非约束友元,友元模板类型参数与模板类类型参数是不同的:
template<typename T>
class ManyFriend
{
template<typename C, template D> friend void show2(C&, D&);
};
程序清单类模板-10是一个使用非约束友元的例子。其中,函数调用show2(hfi1, hfi2)与下面的具体化匹配:
void show2<ManyFriend<int>&, ManyFriend<int>& >
(ManyFriend<int>& c, ManyFriend<int>& d);
因为它是所有ManyFriend具体化的友元,所以能够访问所有具体化的item成员,但它只访问了ManyFriend<int>对象。
同样,show2(hfi1, hfi2)与下面具体化匹配:
void show2<ManyFriend<double>&, ManyFriend<int>& >
(ManyFriend<double>& c, ManyFriend<int>& d);
它也是所有ManyFriend具体化的友元,并访问了ManyFriend<int>对象的item成员和ManyFriend<double>对象的item成员。
// 类模板-10
// manyfrnd.cpp -- unbound template friend to a template class
#include <iostream>
using std::cout;
using std::endl;
template<typename T>
class ManyFriend
{
private:
T item;
public:
ManyFriend(const T& i): item(i) {}
template <typename C, typename D> friend void show2(C&, D&);
};
template <typename C, typename D> void show2(C& c, D& d)
{
cout << c.item << ", " << d.item << endl;
}
int main()
{
ManyFriend<int> hfi1(10);
ManyFriend<int> hfi2(20);
ManyFriend<double> hfdb(10.5);
cout << "hfi1, hfi2: ";
show2(hfi1, hfi2);
cout << "hfdb, fhi2: ";
show2(hfdb, hfi2);
return 0;
}
10. 模板别名(C++11)
如果能为类型指定别名,将很方便,在模板设计中尤其如此。可使用typedef为模板具体化指定别名:
// define 3 typedef aliases
typedef std::array<double, 12> arrd;
typedef std::array<int, 12> arri;
typedef std::array<std::string, 12> arrst;
arrd gallons;
arri days;
arrst months;
C++11新增了一项功能——使用模板提供一系列别名,如下所示:
typename<typename T>
using arrtype = std::array<T, 12> // template to create multiple aliases
这将arrtype定义为一个模板别面,可使用它来指定类型,如下所示:
arrtype<double> gallons;
arrtype<int> days;
arrtype<std::string> months;
C++11允许将语法using=用于非模板。用于非模板时,这种语法与常规typedef等价:
typedef const char* pc1;
using pc2 = const char*; //using = syntax
typedef const int *(*pa1)[10]; //typedef syntax
using pa2 = const int*(*)[10]; //using = syntax
这种语法的可读性更强,它让类型名和类型信息更清晰。
C++11新增的另一项模板功能是可变参数模板(variadic template),让您能够定义这样的模板类和模板函数,即可接受可变数量的参数。