C++11新标准

注:本文所有内容均来自侯捷老师的C++视频,非转载

一、模板

参数数量不定的模板参数

当使用typename…Types关键字时,表明参数个数随意,参数类型也随意。可以用于函数递归,每次减少一个参数。

示例代码

void print() {
	cout << "11111" << endl;
}

template<typename T,typename...Types>
void print(const T& firstArg, const Types&...args) {
	cout << firstArg << endl;
	print(args...);
}

  int main()
  {
	  print(7.5, "hello", 2021, 42);
	  system("pause");
	  return 0;
  }

在这里插入图片描述
每次的函数调用都会使用第一个参数作为firstArg,其余的作为剩下的其他参数,当最后一个参数作为firstArg的时候,此时调用print参数已经为空。所以需要一个print()空参数的函数,作为调用,为了证明这点,我在void print()中输出 “111”。

特化&泛化

调用会优先选择特化的,如下代码所示

void print() {
	cout << "11111" << endl;
}

template<typename T,typename...Types>
void print(const T& firstArg, const Types&...args) {
	cout << firstArg << endl;
	print(args...);
}

template<typename...Types>
void print(const Types&...args) {
   cout << 111 << endl;
	print(args...);
}

  int main()
  {
	  print(7.5, "hello", 2021, 42);
	  system("pause");
	  return 0;
  }

在这里插入图片描述

二、Spaces in template Expressions

vector<list<int> >//	之前的版本要求两个>之间空格
vector<list<int>>  // OK since C++ 11

三、nullptr

C++11出现了nullptr用来表示空指针,防止NULL=0时表示整数而不是指针, 出现模棱两可的情况

void f(int);
void f(void*);
f(0);		//call f(int)
f(NULL); 	//call f(int) if NULL is 0, ambiguous otherwise
f(nullpter): //call f(void*)

四、auto

在C++11中,我们使用auto像函数去使用,不必指明每个参数的类型,编译器会自动指明函数的类型

auto i=42;  //i has type int
double f():
auto d= f();	//d has type double

当类型特别长,或者type很复杂,一时间想不出来,使用auto尤其有用。

不能因为有了auto,就什么地方都使用,而不加以思考

vector<string>v;
...
auto pos =v.begin();	//pos has type vector<string>::iterator
auto I =[](int x)->bool{	//I has the type of a lambda tanking an int and returning a bool
...,
};

五、Uniform Initialization

C++11提供了一个统一的大括号初始化方法,当编译器看到{t1,t2…n}便做出一个initializer_list,它关系至一个arrat<T,n>。调用函数时该array内的元素可被编译器逐一传给函数。但若该函数参数为initializer_list,调用者却不能给予数个T参数然后以为它们会自动转为一个initializer_list传入

int values[]{1,2,3};
vector<int>v{1,2,3,4,5};
vector<string> cities{"Beijing",Wuhan"};
complex<double> c{4.0,3.0}; //复数 4.0+3.0i

如果我们使用列表初始化值存在丢失信息的风险,则编译器将报错:

int a{double}; //Error, 缩小赋值

六、initializer_list<>

class P{
 public:
 	P(int a, int b)
 	{
 	cout<<"a="<<a<<"b="<<b<<endl;
 	}
 	P(initializer_list<int>initlist)
 	{
		for(auto i:initlist)
		{
		cout<<i<<" ";
		}
		cout<<endl;
	}
};

P p (75,5);  //P(int ,int ),a=75,b=5
P q{77,5};   //P(initializer_list<int>),value =77,5
P g{77,1,2};	//P(initializer_list<int>initlist),value=77,1,2
P h={77,5};	//P(initializer_list<int>initlist),value=77 ,5

有了initializer_list之后,对于STL的container的初始化就方便多了,比如以前初始化一个vector需要这样:

vector v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);

c++11添加了initializer_list后,我们可以这样初始化

std::vector v = { 1, 2, 3, 4 };

需要注意的是,initializer_list对象中的元素永远是常量值,我们无法改变initializer_list对象中元素的值。并且,拷贝或赋值一个initializer_list对象进行一个浅拷贝,只是把指针拷贝过去,两个指针指向同一个对象,这是危险的!

七、explicit

用途很少,主要用在构造函数上,表达要明确的调用函数,不需要转换

class P
{
public:
	P(int a,int b)
	{
	cout<<"	P(int a,int b)"<<endl;
	}
	P(initializer_list<int>)
	{
	cout<<"initializer_list<int>"<<endl;
	}
	explicit P(int a,int b,int c)
	{
	cout<<"explicit P(int a,int b,int c)"<<endl;
	}
};




P p1(77,5);		//P(int a,int b)"
P p2{77,5};		//initializer_list<int>
P p3{77,5,42};		//initializer_list<int>
P p4={77,5};		//initializer_list<int>
P p5={77,5,42};		//Error,传给Pinitializer_list会使用explicit构造P
P p4(77,5,42);	 	//explict P(int a,int b,int c)

八、for(decl:coll){statement}

for(int i:{2,3,4,5,7,8,9,10})
{ 
	cout<<i<<endl;
}
vector<double>vec;
...
for(auto elem:vec)
{
 cout<<elem<<endl;
}

for(auto& elem:vec)
{
	elem*=3;
} 

九、=default,=delete

如果你自行定义了一个构造,那么编译器就不会再给你一个默认构造。
如果你强制加上 =default, 就可以重新获得并使用默认构造。

class Zoo {
public:
	Zoo(int i1,int i2):d1(i1),d2(i2){}
	Zoo(const Zoo&) = delete;
	Zoo(Zoo &&) = default;
	Zoo& operator=(const Zoo&) = default;
	Zoo& operator=(const Zoo&&) = delete;
	virtual ~Zoo();

private:
	int d1, d2;
};

十、Alias Template(别名)

template <typename T>
using Vec = std::vector<T,allocator<T>>
Vec<int>coll;	
//等同于 std::vector<int,allocator<int>> coll;

十一、noexcept、override

在函数名后添加noexcept,保证这个函数不会丢出异常

void foo() noexcept; //=void foo() except(true)

也可以添加无异常条件

void swap(Type &x,Type &y)noexcept(except(x.swap(y)))
{
	x.swap(y);
}
//如果x.swap(y)不丢异常,则swap不丢异常

十二、decltype

使用新的decltype关键字,你可以让编译器找出一个表达式的类型。

map<string,float>coll;
...
decltype(coll)::value_type elem;

通过decltype获取类型,然后声明一个变量(容器都有value_type),然后就可以知道这个容器的类型。

decltype的应用

1、used to declare return types

template<typename T1, typename T2>
decltype(x + y) add(T1 x, T2 y);

//以上方法在C++11之前不可以,因为返回的表达式使用了未定义的变量

//C++11之后
template<typename T1, typename T2>
auto add(T1 x, T2 y)->decltype(x + y) ;

2、use it in metaprogramming

template<typename T>
//T必须是个容器
void test_decltype(T obj)
{
	map<string, float>::value_type elem1;
	//当我们手上有type,可取其inner typedef,没问题

	map<string, float>coll;
	decltype(coll)::value_type elem2;
	//面对obj取其class type 的inner typedef 
	//因为如今我们有了工具的decltype

	//如果是接受任意参数 T obj

	//如今有了decltype我可以这样
	typedef typename decltype(obj)::iterator iType;
	typedef typename T::iterator iType;
	decltype(obj) anotherObj(obj);
}

3、pass the type of a lambda
面对lambda,我们手上往往没有object,没有type。
要获得其type,就得借助于decltype


auto cmp = [](const Person& p1, const Person& p2) {
	return p1.lastname() < p2.lastname() ||
		(p1.lastname() == p2.lastname() &&
			p1.firstname() < p2.firstname());
};
...
std::set<Person, decltype(cmp)>coll(cmp);

十三、lambdas

[](参数){操作;}

在这里插入图片描述
示例:删除一定范围内的数值

	vector<int>vi{ 5,2,28,94,30,15,72,46,23,15 };
	int x = 30;
	int y = 100;
	//删除30 到100之间的数
	vi.erase(remove_if(vi.begin(), vi.end(), [x, y](int n) {return x < n&&n < y; }));
	
	for (auto elem : vi)
	{
		cout << elem << endl;
	}
	
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值