这部分大体包括语法糖(封装优化好的库函数或模块),以及一些令代码更简洁、可读性更强的函数与库。
C++ 17以前,使用for循环遍历map / unordered_map 时候需要声明一个中间变量(通常无意义),通过中间变量和first、second关键字访问key和value。
C++ 17引入结构化绑定,其将array、tuple或struct的成员绑定到一组变量*
// 1.构建一个描述人的结构体
struct Person {
int age = 0;
std::string name;
};
// 2. 获得一个结构体对象,姓名:”ABC“,年龄:99
Person getPerson() {
return Person{99, "ABC"};
};
// 3. 结构化绑定
auto [age, name] = getStruct();
// C++ 17 以前遍历 map,声明无意义引用elem
for(const auto& elem : map){
const auto& key = elem.first;
const auto& value = elem.second;
std::cout << elem.first << ": " << elem.second << std::endl;
}
// C++ 17
for(const auto& [key, value]: map){
std::cout << key << ": " << val << std::endl;
}
*: 严格来说,结构化绑定的结果并不是变量,即 key 和 value 并非变量,C++标准称之为“别名”,因此它们不能被lambda表达式捕获,但是 gcc 并没有遵循 C++ 标准,所以下面代码在gcc下可以编译,clang则编译不过。
for(const auto& [key, value]: map){
[&key, &value]{
std::cout << key << ": " << value << std::endl;
}();
}
若使用Clang作为编译前端,可以在lambda表达式捕获时显式引入一个引用变量通过编译。
for(const auto& [key, value]: map){
[&key = key, &value = value]{
std::cout << key << ": " << value << std::endl;
}();
}
但是!该限制在C++ 20 中已经被删除,所以在C++ 20 的标准中gcc和Clang都可以捕获结构化绑定的对象了。
std::tuple 的推导指引 - cppreference.com
在C++ 17以前,构造 std::pair / std::tuple 时必须指定数据类型或使用std::make_pair/std::make_tuple
函数,C++ 17为std::pair/std::tuple
新增了推导规则,可以不再显示指定类型。
// C++ 17 以前
std::pair p1{99, "ABC"s};
auto p1 = std::make_pair(99, "ABC"s);
// C++ 17 pair的具体类型隐式声明
std::pair p3{99, "ABC"s};
if constexpr 语句是编译期的 if 判断语句,它可以在编译阶段,根据模板参数的值编译相应的段落,因此可以在“范型编程中使用” ;若是将if判断放到运行时,可能会造成性能损耗。在C++17 编译期的条件判断需要通过SFINAE 机制 或 模版重载 实现;
// C++ 17 使用变长参数模板 和 if constexpr 实现数字求和
template
auto sum()
{
if constexpr (0 == sizeof...(Ns))
return N;
else
return N + sum();
}
// 调用
sum<1, 2, 3>(); // returns 6
在没有if constexpr 之前,普通的 if - else 是在执行期进行条件判断,因此无法在泛型编程中无法使用。在这个求和的例子中,无法使用 if - else 判断当前变长参数的长度,因此需要额外写一个函数模板处理单模版参数的情况。
// 一个模板参数时的函数模板?拗口
template
int sum()
{
return N;
}
// 模板参数 > 2 个时调用此模板
template
int sum()
{
return N1 + sum();
}
// 调用
sum<1, 2, 3>(); // returns 6
C++ 17 支持在 if 语句内的条件判断之前增加一个初始化语句,将仅用于 if 语句内部的变量声明在此,提升代码可读性。
可以包含
if (初始化语句; 条件) 语句 else 语句
switch (初始化语句; 条件) 语句
std::map m;
std::mutex mx;
extern bool shared_flag; // guarded by mx
int demo()
{
if (auto it = m.find(10); it != m.end()) { return it->second.size(); }
if (char buf[10]; std::fgets(buf, 10, stdin)) { m[0] += buf; }
if (std::lock_guard lock(mx); shared_flag) { unsafe_ping(); shared_flag = false; }
if (int s; int count = ReadBytesWithSignal(&s)) { publish(count); raise(s); }
if (const auto keywords = {"if", "for", "while"};
std::ranges::any_of(keywords, [&tok](const char* kw) { return tok == kw; }))
{
std::cerr << "Token must not be a keyword\n";
}
}