C++98的经典语言特性
1.非类型模板参数
bitset将bit个数作为实参,不同类型之间不可进行赋值或比较。例如:
#include <bitset>
std::bitset<1> flags1;
std::bitset<2> flags2;
std::bitset<3> flags3;
flags3.set(0, true);
flags3.set(1, false);
flags3.set(2, false);
flags3[2] = true;
int size = sizeof(flags3);
2.模板参数默认值
类模板可以拥有默认实参。例如:
template <typename T, typename container = std::vector<T>>
class Test
{
// TODO:
}
Test<int> test; // 相当于Test<int, std::vector<int>> test;
3.关键字typename
typename用来指明紧跟其后的是个类型。
template <typename T>
class Test
{
typename T::SubType * ptr; // typename指明SubType是T内的子类型.
}
例如我们使用Q类型来实例化上述模板:
class Q
{
typedef int SubType;
}
Test<Q> test; // 用于实例化的Q类型内部必须包含SubType子类型.
4.成员模板
a) 类的成员函数可以是模板,然而成员模板不可以是虚函数。
b) 成员模板的一个特殊形式是模板构造函数,它在对象被复制时给予隐式类型转换的能力。
template <typename T>
class Test
{
template <typename U>
Test(const Test<U>& x);
// ...
}
int main()
{
Test<double> t1;
Test<double> t2(t1); // 隐式调用默认拷贝构造函数.
Test<double> t3 = t1; // 隐式调用默认拷贝构造函数.
Test<int> t4(t1); // 显式调用模板构造函数.
// ...
return 0;
}
5.嵌套式类模板
template <typename T>
class Test
{
template <typename T2>
class NestedClass
{
// ...
}
}
6.基础类型的明确初始化
“一个明确的构造函数调用,但不给实参”这样的语法,基础类型会被设定初始值为0:
int i; // 初始化为默认值.
int j = int(); // 调用不给实参的构造函数,初始化为0.
int k{}; // 调用空的参数列表初始化(C++11新特性),初始化为0.
由此推广到模板函数:
template <typename T>
void f()
{
T x = T(); // 若x为基础类型,则被初始化为0.
//T x{}; // C++11支持的新特性,作用同上。
}
7.main()定义式
在此强调一下main函数“正确且具有可移植性”的定义形式只有两种:
// style1.
int main()
{
// ...
return 0; // C++中此“return 0;”语句可以不写,系统自动添加(不适用于C).
}
// style2.
int main(int argc, char * argv[])
{
// argc为命令行参数个数,默认为1
// argv为命令行参数指针,默认仅指向当前可执行文件的绝对路径.
// char * argv[] 也可写成 char ** argv.
// ...
// return 0; // C++已对其隐晦的定义了.
// 以下函数也可终止函数的运行:exit()、quick_exit()、terminate().
}