C++新标准 侯捷(一) 语言(上)

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


1.variadic templates(可变参数模板)

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");
}

2.Spaces in Template Expression、nullptr and std--nullptr_t、Automatic Type Deduction with auto

Spaces in template:

vector >//旧版
vector>//since C++11

空指针(新关键字nullptr):

void f(int);
void f(void*);

f(null);//调用f(int)
f(nullptr);调用f(void*)

auto:自动识别类型

3.Uniform initialization(一致性初始化)

之前:初始化发生在小括号,大括号和赋值运算符中。

现在:可以都用大括号来初始化,直接跟在变量名后。

其实是利用了一个事实,编译器看到{t1,t2,...tn}便做出一个initializer_list,它关联至一个array。调用函数(例如ctor)时该array内的元素可被编译器分解逐一传给函数。但若函数参数是个initializer_list,调用者却不能给予数个T参数然后以为它们会自动转为initializer_list传入。

 

4.Initializer Lists

对于大括号来说,不允许窄化的转换,不过也有一些平台仅会给出警告。比如:

int x1(5.2);         //x1=5
int x2{5.2};         //报错:narrowing
char c1{7};          //OK

当用{ }时,编译器会去调用一个私有的构造器,它会先准备好一个容器array。然后会传进来迭代器的头和大小。

initializer_list它有一个array在支撑,并且只是传入一个指针指向array,并不是拥有array(只是浅拷贝,拷贝的只是指针)

5.explicit for ctor taking more than one arguement

explicit(明白地,明确地)这个关键字用途比较少,主要用于构造函数中。

C++新标准 侯捷(一) 语言(上)_第1张图片

比如说上例:不要编译器像左边那样自动把5转换为5+0i,就加上explicit关键字,这样编译器遇到+5时便会报错,就是说你不要自动地帮我调用,我要明白地,明确地使用,总之就是隐式转换之后来调用就不行

6.range-based for statement

for循环的一种特殊写法:

for(decl:coll){
    statement
}

其实就是把右边的容器用迭代器指出来,用++的形式遍历一遍,遍历中的每一个元素都赋值到左边声明的变量中。

7.=default,=delete

1.如果你自己定义了一个ctor,那么编译器就不会再给你一个默认构造函数。如果你强制加上一个=default,就可以重新获得并使用默认构造器,只能用在big-five中那5个函数(构造器,拷贝构造函数,赋值运算符,析构函数,移动构造函数(可能需要修改))中。

2.=delete就是我不要的意思,必须出现在声明时,告诉编译器不要定义,可用于任何函数上(=0只能用于虚函数上)。

3.构造器可以有很多个,但是拷贝构造器只能有一个,如果已经写了一个,再用=default就会报错。再用=delete也不行,因为已经写出来了,又要编译器缺省,编译器不知道使用者什么意思,于是报错。

4.当然也不是所有函数都可以用=default,比如void func1()=default;

5.=default和=delete不能并存。

一个类只要带指针成员,就可以断定需要自己写Big-Three(构造函数,析构函数,拷贝构造函数),如果不带,基本不用,用默认的那一条就够了。

tips:不让一般用户代码,只让指定的友元或者成员代码拷贝,比如boost,以下面方法实现:C++新标准 侯捷(一) 语言(上)_第2张图片

8.Alias templates(化名模板)

template
using Vec = std::vector>;      //标准vector使用自己的分配器

不可以用define,原因是如果用define,那么Vec coll;相当于template std::vector>;

这显然不符合我们的意思。

typedef也无法达到相同效果,因为typedef不接受参数。

模板参数是模板:(之所以讲这个是为后面化名的一个应用做铺垫)

C++新标准 侯捷(一) 语言(上)_第3张图片

 1.左边传入的是容器,却想对它的类型做文章,不可取。

2.因为用的是模板,所以传过去的必须是个对象。

9.Template template parameter

一个模板是另一个模板的参数之一,而这个作为参数的模板的参数类型为外层模板的类型参数T,比如:

template class Container >

如果不用化名,直接调用XCls会报错,错误的原因是因为vector其实有两个参数,而下面语句中的Container c;仅一个参数,而编译器无法做出参数推导,因此不匹配。

C++新标准 侯捷(一) 语言(上)_第4张图片

10.Type Alias、noexcept、override、final

A.Type Alias(近似于typedef)

//typedef void(*func)(int,int); type alias,等价于下面这种
using func = void(*)(int,int);

1.这里的func代表一个指向函数的指针。

2.函数的名称就是函数的指针,指向函数的地址。比如:

void example(int,int){}
func fn = example;

 B.noexcept

 void foo() noexcept;(=void foo() noexcept(true);)表示这个函数不会丢出异常。

 A调用B,B发生异常,中断,如果B没有处理,就会将异常传给A,异常往源头跑。如果还没有处理,就会调用std::terminate()。

C++新标准 侯捷(一) 语言(上)_第5张图片

比如vector,要让它成长,就不能让它发生中断,因此这里不抛出异常。

 成长的容器:只有vector和deque(?)。

C.override

改写,假设没有重写的话,编译器就会报错,否则编译器怎么知道你要重写。

C++新标准 侯捷(一) 语言(上)_第6张图片

 D.final

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]
}

 

你可能感兴趣的:(C++新标准 侯捷(一) 语言(上))