C++17 部分实用特性

2017年12月6日,C++17 标准正式发布!鉴于目前国内介绍 C++17 新特性的资料不多,而且就算提到了 C++17,也无非以下两类:一类只是提了一下有哪些新特性,而没详细讲解用法;另外一类就是在畅想 concept , module 等本来期望着能进 C++17, 最终却无缘入围的功能。因此,本人决定从国外的视频中搬运一些详解 C++17 新特性的学习资料,供大家围观。

本文部分内容参考了 Bryce Lelbach 主讲的视频 C++17 Features – An Introduction to C++17 Via Inspiring Examples ,这位老兄特别健谈,一个人连续讲解了一个半小时没有休息,向他致敬!另外,由于本人最近手头事有点多,所以边写边更,速度慢请见谅!理解有误的地方也请各位同仁批评指正!

构造函数的模板推导 (Class template deduction)

直接上代码,大家先有个直观感受

#include <iostream>
#include <string>
 
using namespace std;
 
int main()
{
	pair p(3, 3.5); //now
	cout << p.first << "  " << p.second << endl;
	
	pair <int, double> p2(3, 3.5); //before
	cout << p2.first << "  " << p2.second << endl;
 
	pair p3(3.5,"abc"); //now, 自动推导为 pair<double, const char*> 类型
	cout << p3.first << "  " << p3.second << endl;
	
 	/*
	p3.second.length(); //提示出错, gcc 7.1 的提示信息为:
		[Error] request for member 'length' in 'p3.std::pair<double, const char*>::second', which is of non-class type 'const char*'
	*/
 
	return 0;
}

可以看到,在以前,必须手动指定 pair 的模板参数。现在呢,可以通过你传进去的构造参数的类型自动推导生成的 pair 的类型了。不过要当心了,看那个 p3 ,第二个模板参数推导出的类型是 const char* ,不是 string !

当然,这种自动模板类型推导也适用于 vector , tuple (元组) 等其他容器,例如:

#include <iostream>
#include <vector>
 
using namespace std;
 
int main()
{
	vector v = {1.2, 5.6, 8.7};
 
	for(const auto & ele : v) {
		cout << ele << endl;
	}
 
	return 0;
}
结构化绑定 (Structured bindings)

记得以前学 C 语言时,要想让一个函数能返回两个值的话,用的是参数列表里传指针的形式;或者你自己再定义一个结构体也行。后来么,有了 C++ 里的 pair ,虽然理论上可以用这个返回两个参数,但是实际操作中用的还是不多。

当然了么,人心是贪婪的。既然能返回两个值,我肯定就会想着如何返回三个值 ~~~ 貌似用 tuple 里的 get<0>() get<1>() get<2>() 太烦了点。

而结构化绑定就是这样一种利器,能帮你更优雅的实现这些想法。

#include <iostream>
#include <string>
#include <tuple>
 
using namespace std;
 
pair<int, string> get_record()
{
	return pair(0, "Jebediah");
}
 
auto get_record2() //这个函数的返回值类型声明利用了 C++14 中自动推导返回类型的特性, 等价于下面一个版本
{
	return tuple(1, "Bill", "engineer");
}
 
/*
tuple<int, const char*, const char*> get_record2()
{
	return tuple(1, "Bill", "engineer");
}
*/
 
int main()
{
 
	auto [id, name] = get_record();
	cout << id << "   " << name << endl;
 
	auto [id2, name2, job2] = get_record2();
	//注意,这里要是不写成 id2, name2, ... 的话,就和上面的变量名起冲突了
	cout << id2 << "   " << name2 << "   " << job2 << endl;
 
	return 0;
}

最近 map 这个容器用的挺多的,干脆来介绍一下它在 map 中的一些应用:

#include <iostream>
#include <string>
#include <map>
 
using namespace std;
 
 
int main()
{
	map<int, string> m = {
		{0, "Jebediah"},
		{1, "Bob"},
		{2, "Bill"},
	}; //这边貌似就不能用 map m = { {0, "Jebediah"}, ...}; 这种方式做自动类型推导了, 应该是标准还没发展到那么智能吧
	//g++ 7.1 报错:	[Error] no matching function for call to 'map(<brace-enclosed initializer list>)'
 
 
	/* now in C++17 */
	for(const auto & [key, value] : m) {
		cout << key << "   " << value << endl;
	}
	cout << endl;
 
 
 
	/* before */
	for(const pair<const int, string> & result : m) {
		cout << result.first << "   " << result.second << endl;
	}
	cout << endl;
 
	/*
	  当然,如果你觉得用 first, second 去取 key, value 很丑陋的话,
	  你也可以借助 .* 运算符给他们取个别名,借机骚一波
	 */
	typedef pair<const int, string> find;
	const int find:: * key = &find::first;
	string find:: * value = &find::second;
 
	for(const pair<const int, string> & result : m) {
		cout << result.*key << "   " << result.*value << endl;
	}
 
	/* 不过鉴于用 .* 运算符写起来太晦涩了,所以第三种写法就算了吧 */

	return 0;
}

你可能要说了,C++11 里的 tie 也能完成这些功能啊。不好意思,Bryce 同志在他的幻灯片里罗列了一大堆 tie 的劣处:

/* 1 */
std::tuple<double, double, double> t = // ...
 
double x, y, z;
 
std::tie(x, y, z) = t; // correct 
 
 
/* 2 */
std::tuple<double, double, double> t = // ...
 
double x, y, z;
 
std::tie(y, y, z) = t; // ^ UH-OH : no warning for repeated names.
 
 
/* 3 */
std::tuple<double, double, double> t = // ...
 
double &x, &y, &z; // COMPILE ERROR
				   // Uninitialized refs.
 
std::tie(x, y, z) = t;
 
 
/* 4 */
std::tuple<double, double, double> t = // ...
 
double const x, y, z;
 
std::tie(x, y, z) = t; // COMPILE ERROR
					   // Assignment to const.
选择语句中的初始化器 (Selection Statements with Initializers)

顾名思义,就是现在能在 if 语句中做一些初始化工作了

#include <iostream>
#include <string>
#include <map>
 
using namespace std;
 
int main()
{
	map<int, string> m = {
		{0, "Jebediah"},
		{1, "Bob"},
		{2, "Bill"},
	};
 
	/* now */
	if(auto it = m.find(1); it != m.end()) {
		auto [key, value] = *it;
		cout << value << endl;
	}
 
	/* before */
	auto it = m.find(1);
	if(it != m.end()) {
		cout << it->second << endl;
	}
 
	return 0;
}
 

更多特性,未完待续。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值