C++2.0新特性包括语言和标准库两个层面,后者以头文件形式呈现。
Compiler support for C++11 and C++14等网站用于查询自己的编译器对C++2.0的支持度
目录
1.variadic templates(可变参数模板)
2.Spaces in Template Expression、nullptr and std--nullptr_t、Automatic Type Deduction with auto
3.Uniform initialization(一致性初始化)
4.Initializer Lists
5.explicit for ctor taking more than one arguement
6.range-based for statement
7.=default,=delete
8.Alias templates(化名模板)
9.Template template parameter
10.Type Alias、noexcept、override、final
A.Type Alias(近似于typedef)
B.noexcept
C.override
D.final
typename... (有个小技巧是1+n-1然后不断递归变成1+n-2,变成1+0甚至0截止,比如以下代码)
#include
#include
using std::bitset;
void print() {}//这里是当下面代码迭代到参数数为0时调用的
template
void print(const T& firstArg, const Types&... args) //...的位置是因语法定义不同而不同
{
std::cout << firstArg << std::endl;
print(args...);
}
void main() {
print(7.5,"hello",bitset<16>(377),42);
system("pause");
}
Spaces in template:
vector >//旧版
vector>//since C++11
空指针(新关键字nullptr):
void f(int);
void f(void*);
f(null);//调用f(int)
f(nullptr);调用f(void*)
auto:自动识别类型
之前:初始化发生在小括号,大括号和赋值运算符中。
现在:可以都用大括号来初始化,直接跟在变量名后。
其实是利用了一个事实,编译器看到{t1,t2,...tn}便做出一个initializer_list
对于大括号来说,不允许窄化的转换,不过也有一些平台仅会给出警告。比如:
int x1(5.2); //x1=5
int x2{5.2}; //报错:narrowing
char c1{7}; //OK
当用{ }时,编译器会去调用一个私有的构造器,它会先准备好一个容器array。然后会传进来迭代器的头和大小。
initializer_list它有一个array在支撑,并且只是传入一个指针指向array,并不是拥有array(只是浅拷贝,拷贝的只是指针)。
explicit(明白地,明确地)这个关键字用途比较少,主要用于构造函数中。
比如说上例:不要编译器像左边那样自动把5转换为5+0i,就加上explicit关键字,这样编译器遇到+5时便会报错,就是说你不要自动地帮我调用,我要明白地,明确地使用,总之就是隐式转换之后来调用就不行。
for循环的一种特殊写法:
for(decl:coll){
statement
}
其实就是把右边的容器用迭代器指出来,用++的形式遍历一遍,遍历中的每一个元素都赋值到左边声明的变量中。
1.如果你自己定义了一个ctor,那么编译器就不会再给你一个默认构造函数。如果你强制加上一个=default,就可以重新获得并使用默认构造器,只能用在big-five中那5个函数(构造器,拷贝构造函数,赋值运算符,析构函数,移动构造函数(可能需要修改))中。
2.=delete就是我不要的意思,必须出现在声明时,告诉编译器不要定义,可用于任何函数上(=0只能用于虚函数上)。
3.构造器可以有很多个,但是拷贝构造器只能有一个,如果已经写了一个,再用=default就会报错。再用=delete也不行,因为已经写出来了,又要编译器缺省,编译器不知道使用者什么意思,于是报错。
4.当然也不是所有函数都可以用=default,比如void func1()=default;
5.=default和=delete不能并存。
一个类只要带指针成员,就可以断定需要自己写Big-Three(构造函数,析构函数,拷贝构造函数),如果不带,基本不用,用默认的那一条就够了。
template
using Vec = std::vector>; //标准vector使用自己的分配器
不可以用define,原因是如果用define,那么Vec
这显然不符合我们的意思。
typedef也无法达到相同效果,因为typedef不接受参数。
模板参数是模板:(之所以讲这个是为后面化名的一个应用做铺垫)
1.左边传入的是容器,却想对它的类型做文章,不可取。
2.因为用的是模板,所以传过去的必须是个对象。
一个模板是另一个模板的参数之一,而这个作为参数的模板的参数类型为外层模板的类型参数T,比如:
template class Container >
如果不用化名,直接调用XCls
//typedef void(*func)(int,int); type alias,等价于下面这种
using func = void(*)(int,int);
1.这里的func代表一个指向函数的指针。
2.函数的名称就是函数的指针,指向函数的地址。比如:
void example(int,int){}
func fn = example;
void foo() noexcept;(=void foo() noexcept(true);)表示这个函数不会丢出异常。
A调用B,B发生异常,中断,如果B没有处理,就会将异常传给A,异常往源头跑。如果还没有处理,就会调用std::terminate()。
比如vector,要让它成长,就不能让它发生中断,因此这里不抛出异常。
成长的容器:只有vector和deque(?)。
改写,假设没有重写的话,编译器就会报错,否则编译器怎么知道你要重写。
1.对于父类写上final,代表继承体系的最后一个,不要别人来继承自己,比如:
struct Bsse1 final{};
struct Derived1:Base1{};
//[Error] cannot derive from 'final' ...
2.对虚函数用,则不可以被重写。
struct Base2{
virtual void f() final;
}
struct Derived2:Base2{
void f();
//[Error]
}