在C++11中,decltype操作符,用于查询表达式的数据类型。
语法:decltype(expression) var;
decltype推导规则(按步骤):
1)如果expression是一个没有用括号括起来的标识符,则var的类型与该标识符的类型相同,包括const等限定符。
2)如果expression是一个函数调用,则var的类型与函数的返回值类型相同(函数不能返回void,但可以返回void *)。
3)如果expression是一个左值(能取地址)(要排除第一种情况)、或者用括号括起来的标识符,那么var的类型是expression的引用。
4)如果上面的条件都不满足,则var的类型与expression的类型相同。
如果需要多次使用decltype,可以结合typedef和using。
int func(int x,double y);
等同:
auto func(int x,double y) -> int;
将返回类型移到了函数声明的后面。
auto是一个占位符(C++11给auto新增的角色), 为函数返回值占了一个位置。
这种语法也可以用于函数定义:
auto func(int x,double y) -> int
{// 函数体。
}
C++14标准对函数返回类型推导规则做了优化,函数的返回值可以用auto,不必尾随返回类型。
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。template
auto func(T1 x, T2 y) -> decltype(x + y)
{// 其它的代码。decltype(x+y) tmp = x + y;cout << "tmp=" << tmp << endl;return tmp;
}int main()
{func(3, 5.8);
}
模板类具体化(特化、特例化)有两种:完全具体化和部分具体化。
具体化程度高的类优先于具体化程度低的类,具体化的类优先于没有具体化的类。
具体化的模板类,成员函数类外实现的代码应该放在源文件中。
eg:
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。// 类模板
template
class AA { // 类模板。
public:T1 m_x;T2 m_y;AA(const T1 x, const T2 y) :m_x(x), m_y(y) { cout << "类模板:构造函数。\n"; }void show() const;
};template
void AA::show() const { // 成员函数类外实现。cout << "类模板:x = " << m_x << ", y = " << m_y << endl;
}
/// 类模板完全具体化
template<>
class AA {
public:int m_x;string m_y;AA(const int x, const string y) :m_x(x), m_y(y) { cout << "完全具体化:构造函数。\n"; }void show() const;
};void AA::show() const { // 成员函数类外实现。cout << "完全具体化:x = " << m_x << ", y = " << m_y << endl;
}
/// 类模板部分具体化
template
class AA {
public:T1 m_x;string m_y;AA(const T1 x, const string y) :m_x(x), m_y(y) { cout << "部分具体化:构造函数。\n"; }void show() const;
};template
void AA::show() const { // 成员函数类外实现。cout << "部分具体化:x = " << m_x << ", y = " << m_y << endl;
}
/int main()
{// 具体化程度高的类优先于具体化程度低的类,具体化的类优先于没有具体化的类。AA aa1(8, "我是一只傻傻鸟。"); // 将使用完全具体化的类。AA aa2(8, "我是一只傻傻鸟。"); // 将使用部分具体化的类。AA aa3(8, 999999); // 将使用模板类。
}
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。class AA // 普通类AA。
{
public:int m_a;AA(int a) :m_a(a) { cout << "调用了AA的构造函数。\n"; }void func1() { cout << "调用了func1()函数:m_a=" << m_a << endl;; }
};template
class BB:public AA // 模板类BB。
{
public:T1 m_x;T2 m_y;BB(const T1 x, const T2 y,int a) : AA(a) , m_x(x), m_y(y) { cout << "调用了BB的构造函数。\n"; }void func2() const { cout << "调用了func2()函数:x = " << m_x << ", y = " << m_y << endl; }
};int main()
{BB bb(8, "我是一只傻傻鸟。",3);bb.func2();bb.func1();
}
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。template
class BB // 模板类BB。
{
public:T1 m_x;T2 m_y;BB(const T1 x, const T2 y) : m_x(x), m_y(y) { cout << "调用了BB的构造函数。\n"; }void func2() const { cout << "调用了func2()函数:x = " << m_x << ", y = " << m_y << endl; }
};class AA:public BB // 普通类AA。
{
public:int m_a;AA(int a,int x,string y) : BB(x,y),m_a(a) { cout << "调用了AA的构造函数。\n"; }void func1() { cout << "调用了func1()函数:m_a=" << m_a << endl;; }
};int main()
{AA aa(3,8, "我是一只傻傻鸟。");aa.func1();aa.func2();
}
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。template
class BB // 模板类BB。
{
public:T1 m_x;T2 m_y;BB(const T1 x, const T2 y) : m_x(x), m_y(y) { cout << "调用了BB的构造函数。\n"; }void func2() const { cout << "调用了func2()函数:x = " << m_x << ", y = " << m_y << endl; }
};template
class AA:public BB // 普通类AA变成了模板类,才能继承模板类。
{
public:int m_a;AA(int a, const T1 x, const T2 y) : BB(x,y),m_a(a) { cout << "调用了AA的构造函数。\n"; }void func1() { cout << "调用了func1()函数:m_a=" << m_a << endl;; }
};int main()
{AA aa(3,8, "我是一只傻傻鸟。");aa.func1();aa.func2();
}
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。template
class BB // 模板类BB。
{
public:T1 m_x;T2 m_y;BB(const T1 x, const T2 y) : m_x(x), m_y(y) { cout << "调用了BB的构造函数。\n"; }void func2() const { cout << "调用了func2()函数:x = " << m_x << ", y = " << m_y << endl; }
};template
class AA:public BB // 普通类AA变成了模板类,才能继承模板类。
{
public:int m_a;AA(int a, const T1 x, const T2 y) : BB(x,y),m_a(a) { cout << "调用了AA的构造函数。\n"; }void func1() { cout << "调用了func1()函数:m_a=" << m_a << endl;; }
};template
class CC :public BB // 模板类继承模板类。
{
public:T m_a;CC(const T a, const T1 x, const T2 y) : BB(x, y), m_a(a) { cout << "调用了CC的构造函数。\n"; }void func3() { cout << "调用了func3()函数:m_a=" << m_a << endl;; }
};int main()
{CC cc(3,8, "我是一只傻傻鸟。");cc.func3();cc.func2();
}
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。class AA {
public:AA() { cout << "调用了AA的构造函数AA()。\n"; }AA(int a) { cout << "调用了AA的构造函数AA(int a)。\n"; }
};class BB {
public:BB() { cout << "调用了BB的构造函数BB()。\n"; }BB(int a) { cout << "调用了BB的构造函数BB(int a)。\n"; }
};class CC {
public:CC() { cout << "调用了CC的构造函数CC()。\n"; }CC(int a) { cout << "调用了CC的构造函数CC(int a)。\n"; }
};template
class DD {
public:DD() { cout << "调用了DD的构造函数DD()。\n"; }DD(int a) { cout << "调用了DD的构造函数DD(int a)。\n"; }
};template
class EE : public T { // 模板类继承模板参数给出的基类。
public:EE() :T() { cout << "调用了EE的构造函数EE()。\n"; }EE(int a) :T(a) { cout << "调用了EE的构造函数EE(int a)。\n"; }
};int main()
{EE ea1; // AA作为基类。EE eb1; // BB作为基类。EE ec1; // CC作为基类。EE> ed1; // EE作为基类。// EE ed1; // DD作为基类,错误。
}
模板类可以用于函数的参数和返回值,有三种形式:
1)普通函数,参数和返回值是模板类的实例化版本。
2)函数模板,参数和返回值是某种的模板类。
3)函数模板,参数和返回值是任意类型(支持普通类和模板类和其它类型)。
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。template
class AA // 模板类AA。
{
public:T1 m_x;T2 m_y;AA(const T1 x, const T2 y) : m_x(x), m_y(y) { }void show() const { cout << "show() x = " << m_x << ", y = " << m_y << endl; }
};// 采用普通函数,参数和返回值是模板类AA的实例化版本。
AA func(AA& aa)
{aa.show();cout << "调用了func(AA &aa)函数。\n";return aa;
}// 函数模板,参数和返回值是的模板类AA。(函数模板的不规范做法)
template
AA func(AA& aa)
{aa.show();cout << "调用了func(AA &aa)函数。\n";return aa;
}// 函数模板,参数和返回值是任意类型。(函数模板的规范做法)
template
T func(T &aa)
{aa.show();cout << "调用了func(AA &aa)函数。\n";return aa;
}int main()
{AA aa(3, "我是一只傻傻鸟。");func(aa);
}
模板类的友元函数有三类:
1)非模板友元:友元函数不是模板函数,而是利用模板类参数生成的函数。
2)约束模板友元:模板类实例化时,每个实例化的类对应一个友元函数。
3)非约束模板友元:模板类实例化时,如果实例化了n个类,也会实例化n个友元函数,每个实例化的类都拥有n个友元函数。
1)非模板友元示例:
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。template
class AA
{T1 m_x;T2 m_y;
public:AA(const T1 x, const T2 y) : m_x(x), m_y(y) { }// 非模板友元:友元函数不是模板函数,而是利用模板类参数生成的函数,只能在类内实现。//不能重载friend void show(const AA& a){cout << "x = " << a.m_x << ", y = " << a.m_y << endl;}/* friend void show(const AA& a);friend void show(const AA& a);*/
};//void show(const AA& a)
//{
// cout << "x = " << a.m_x << ", y = " << a.m_y << endl;
//}
//
//void show(const AA& a)
//{
// cout << "x = " << a.m_x << ", y = " << a.m_y << endl;
//}int main()
{AA a(88, "我是一只傻傻鸟。");show(a);AA b(88, "我是一只傻傻鸟。");show(b);
}
2)约束模板友元示例:
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。// 约束模板友元:模板类实例化时,每个实例化的类对应一个友元函数。
template
void show(T& a); // 第一步:在模板类的定义前面,声明友元函数模板。template
class AA // 模板类AA。
{friend void show<>(AA& a); // 第二步:在模板类中,再次声明友元函数模板。T1 m_x;T2 m_y;public:AA(const T1 x, const T2 y) : m_x(x), m_y(y) { }
};template
class BB // 模板类BB。
{friend void show<>(BB& a); // 第二步:在模板类中,再次声明友元函数模板。T1 m_x;T2 m_y;public:BB(const T1 x, const T2 y) : m_x(x), m_y(y) { }
};template // 第三步:友元函数模板的定义。
void show(T& a)
{cout << "通用:x = " << a.m_x << ", y = " << a.m_y << endl;
}template <> // 第三步:具体化版本。
void show(AA& a)
{cout << "具体AA:x = " << a.m_x << ", y = " << a.m_y << endl;
}template <> // 第三步:具体化版本。
void show(BB& a)
{cout << "具体BB:x = " << a.m_x << ", y = " << a.m_y << endl;
}int main()
{AA a1(88, "我是一只傻傻鸟。");show(a1); // 将使用具体化的版本。AA a2(88, "我是一只傻傻鸟。");show(a2); // 将使用通用的版本。BB b1(88, "我是一只傻傻鸟。");show(b1); // 将使用具体化的版本。BB b2(88, "我是一只傻傻鸟。");show(b2); // 将使用通用的版本。
}
3)非约束模板友元
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。// 非类模板约束的友元函数,实例化后,每个函数都是每个每个类的友元。
template
class AA
{template friend void show(T& a); // 把函数模板设置为友元。T1 m_x;T2 m_y;
public:AA(const T1 x, const T2 y) : m_x(x), m_y(y) { }
};template void show(T& a) // 通用的函数模板。
{cout << "通用:x = " << a.m_x << ", y = " << a.m_y << endl;
}template <>void show(AA& a) // 函数模板的具体版本。
{cout << "具体:x = " << a.m_x << ", y = " << a.m_y << endl;
}int main()
{AA a(88, "我是一只傻傻鸟。");show(a); // 将使用具体化的版本。AA b(88, "我是一只傻傻鸟。");show(b); // 将使用通用的版本。
}
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。template
class AA // 类模板AA。
{
public:T1 m_x;T2 m_y;AA(const T1 x, const T2 y) : m_x(x), m_y(y) {}void show() { cout << "m_x=" << m_x << ",m_y=" << m_y << endl; }templateclass BB{public:T m_a;T1 m_b;BB() {}void show();};BB m_bb;templatevoid show(T tt);
};template
template
void AA::BB::show() { cout << "m_a=" << m_a << ",m_b=" << m_b << endl;
}template
template
void AA::show(T tt) {cout << "tt=" << tt << endl;cout << "m_x=" << m_x << ",m_y=" << m_y << endl;m_bb.show();
}int main()
{AA a(88, "我是一只傻傻鸟。");a.show();a.m_bb.m_a = "我有一只小小鸟。";a.m_bb.show();a.show("你是一只什么鸟?");
}
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。template
class LinkList // 链表类模板。
{
public:T* m_head; // 链表头结点。int m_len = len; // 表长。void insert() { cout << "向链表中插入了一条记录。\n"; }void ddelete() { cout << "向链表中删除了一条记录。\n"; }void update() { cout << "向链表中更新了一条记录。\n"; }
};template
class Array // 数组类模板。
{
public:T* m_data; // 数组指针。int m_len = len; // 表长。void insert() { cout << "向数组中插入了一条记录。\n"; }void ddelete() { cout << "向数组中删除了一条记录。\n"; }void update() { cout << "向数组中更新了一条记录。\n"; }
};// 线性表模板类:tabletype-线性表类型,datatype-线性表的数据类型。
templateclass tabletype, class datatype, int len>
class LinearList
{
public:tabletype m_table; // 创建线性表对象。void insert() { m_table.insert(); } // 线性表插入操作。void ddelete() { m_table.ddelete(); } // 线性表删除操作。void update() { m_table.update(); } // 线性表更新操作。void oper() // 按业务要求操作线性表。{cout << "len=" << m_table.m_len << endl;m_table.insert();m_table.update();}
};int main()
{// 创建线性表对象,容器类型为链表,链表的数据类型为int,表长为20。LinearList a; a.insert(); a.ddelete(); a.update();// 创建线性表对象,容器类型为数组,数组的数据类型为string,表长为20。LinearList b;b.insert(); b.ddelete(); b.update();
}