C++17 部分新特性一览
C++17 又称 C++1z,是 C++ 的现行标准的非正式名称,正式名称为 “International Standard ISO/IEC Programming Language C++”。C++17 旨在作为大型扩展,最终的投票期于2017年结束。
- 静态断言
static_assert
无需提供出错信息:
/**
* static_assert(bool_constexpr, message) (since C++11)
* static_assert(bool_constexpr) (since C++17)
*/
int main(int argc, char **argv) {
static_assert(1 == 1); // 不需提供第二个参数;
return 0;
}
- 新增 std::basic_string_view, 对外部字符串或字符串片断(string-slice)的引用。该方式只读、不会创建临时对象,string_view 仅使用一个指针和长度值来表示一个字符串对应的视图,在从 char* 进行初始化时的时间成本为 O(n),但接下来的 substr 操作其成本便为 O(1)。在使用时要注意:其引用的字符串生命周期必须要大于等于 string_view 本身。
/**
* constexpr basic_string_view() noexcept; (since C++17)
* constexpr basic_string_view(const basic_string_view& other) noexcept = default; (since C++17)
* constexpr basic_string_view(const CharT* s, size_type count); (since C++17)
* constexpr basic_string_view(const CharT* s); (since C++17)
*/
#include<string_view>
#include<iostream>
int main(int argc, char **argv) {
const char* str = "Hello, world!";
std::string_view sv(str, std::strlen(str));
std::cout << sv.substr(7) << std::endl;
return 0;
}
- 移除 trigraphs 三元符(诸如 “??=” 等)。
- 允许在模板的模板(template template)参数中使用 typename(之前仅允许使用 class):
template<typename T>
struct B { T t(); };
template<template<typename> typename V, typename T>
struct A {
A(V<T>&& v) {}
};
int main(int argc, char **argv) {
A a = B<int>();
return 0;
}
- 编译期静态确定的 if 判断式:if constexpr (expression)。可优化模板泛型编程,比如减少需要自定义的边界模板(循环体+边界条件)。编译时需指定 “-O1” 以上的优化等级,默认情况下编译时求值不会进行:
template <int N, int ...Ns>
auto sum() {
if constexpr (sizeof...(Ns) == 0) {
return N;
} else {
return N + sum<Ns...>();
}
}
int main(int argc, char **argv) {
std::cout << sum<1, 2, 3>() << std::endl;
return 0;
}
- 变长参数模板的 Folding(折叠)运算,可以用来简化模板展开:
template <typename ...Args>
auto sum(Args ...args) { return (0 + ... + args); } // 二元折叠;
int main(int argc, char **argv) {
std::cout << sum(1, 1.3, 1) << std::endl;
return 0;
}
- if 与 switch 语句内的初始化:
int main(int argc, char **argv) {
if (int x = 0; x == 0) {
std::cout << x << std::endl;
}
switch(int y = 0; y) {
case 0: {
std::cout << y << std::endl;
}
}
return 0;
}
- std::variant,可作为类型安全(type-safe)的联合体所使用的容器(union container),同时借助 std::visit 可以代替旧联合体类型使用的 Tagged-Union 方式:
struct A {
int v;
void echo() const {
std::cout << v << std::endl;
}
A(int v) : v(v) {}
A(const A& rhs) { v = rhs.v; }
};
int main(int argc, char **argv) {
std::variant<int, A> v = {A(100)};
std::visit([](auto&& arg) { // 使用 std::visit 在编译时遍历 std::variabt 的内容;
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, A>) { arg.echo(); }
}, v);
return 0;
}
- 结构化绑定,允许对函数返回的结构体对象进行解构:
struct A {
int x;
std::string s;
A() : x(10), s("YHSPY") {}
};
int main(int argc, char **argv) {
const auto [x, s] = A();
std::cout << x << s << std::endl;
return 0;
}
- 利用类模板的构造函数来推导模板参数类型:
template<typename T>
struct A {
A(T t) {}
};
int main(int argc, char **argv) {
A(10); // 不需要 A<int>(10);
return 0;
}
(随时补充)
评论 | Comments