C++17
C++17
历史
[编辑]新 功 能
[编辑]靜態 斷言 static_assert
無 需提供出 錯信息 [1]移 除 trigraphs[2][3]具有 模 板 形式 的 模 板 (template template)参 数 允 许使用 typename(之 前 仅允许使用 class)[4]- std::uncaught_exceptions
取 代 std::uncaught_exception[5][6] - 变长
参 数 模 板 的 Folding运算[6][7] 容器 存 取 操作 表示 方法 的 统一化 (Uniform container access)[8][9]- 连续
型 迭代器 (Contiguous Iterators)[8][10] 新 增 特殊 數學 函數 [11]- 引进Library Fundamentals TS I
中 的 内容 [12]
类模板 的 模 板 参 数 推导
[编辑]pair(5.0, false)
pair<double,bool>(5.0, false)
template <typename T = float>
struct MyContainer {
T val;
MyContainer() : val{} {}
MyContainer(T val) : val{val} {}
// ...
};
MyContainer c1 {1}; // OK MyContainer<int>
MyContainer c2; // OK MyContainer<float>
用 auto声明 非 类型模 板 参 数
[编辑]template <auto... seq>
struct my_integer_sequence {
// Implementation here ...
};
// Explicitly pass type `int` as template argument.
auto seq = std::integer_sequence<int, 0, 1, 2>();
// Type is deduced to be `int`.
auto seq2 = my_integer_sequence<0, 1, 2>();
折 叠表达式
[编辑]- 单元
折 叠:形 如 (... op e) or (e op ...)表 达式,其中 op是 折 叠运算 符 ,e是 未 展 开的模 板 参 数 包 。 二元 折 叠:形 如(e1 op ... op e2)表 达式, 其中 op是 折 叠运算 符 ,e1或 e2是 未 展 开的模 板 参 数 包 。
template <typename... Args>
bool logicalAnd(Args... args) {
// Binary folding.
return (true && ... && args);
}
bool b = true;
bool& b2 = b;
logicalAnd(b, b2, true); // == true
template <typename... Args>
auto sum(Args... args) {
// Unary folding.
return (... + args);
}
sum(1.0, 2.0f, 3); // == 6.0
大 括 号 初 始 化 列 表 的 新 的 自 动推导规则
[编辑]auto x {3};
std::initializer_list<int>
, 现在推导为int
。[13][14]
auto x1 {1, 2, 3}; // error: not a single element
auto x2 = {1, 2, 3}; // x2 is std::initializer_list<int>
auto x3 {3}; // x3 is int
auto x4 {3.0}; // x4 is double
constexpr lambda
[编辑]auto identity = [](int n) constexpr { return n; };
static_assert(identity(123) == 123);
constexpr auto add = [](int x, int y) {
auto L = [=] { return x; };
auto R = [=] { return y; };
return [=] { return L() + R(); };
};
static_assert(add(1, 2)() == 3);
constexpr int addOne(int n) {
return [n] { return n + 1; }();
}
static_assert(addOne(1) == 2);
Lambda函数 中 按值捕获this指 针
[编辑]struct MyObj {
int value {123};
auto getValueCopy() {
return [*this] { return value; };
}
auto getValueRef() {
return [this] { return value; };
}
};
MyObj mo;
auto valueCopy = mo.getValueCopy();
auto valueRef = mo.getValueRef();
mo.value = 321;
valueCopy(); // 123
valueRef(); // 321
内 联变量
[编辑]过去关键
内 联的函数 或 变量必须在 编译单元内 可 达(但 不 一定在访问点之前)在 每 个编译单元 中 都 是 内 联声明 的 内 联变量 必须是 静 态存储器(类静态成员或命名 空 间作用 域 变量),不能 用 于块作用 域 变量或 函数 作用 域 变量。
struct S {
S() : id{count++} {}
~S() { count--; }
int id;
static inline int count{0}; // declare and initialize count to 0 within the class
};
嵌 套的命名 空 间
[编辑]namespace A {
namespace B {
namespace C {
int i;
}
}
}
//The code above can be written like this:
namespace A::B::C {
int i;
}
结构化 绑定
[编辑]变 auto [ x, y, z ] = expr;
,其中exprstd::tuple, std::pair, std::array
using Coordinate = std::pair<int, int>;
Coordinate origin() {
return Coordinate{0, 0};
}
const auto [ x, y ] = origin();
x; // == 0
y; // == 0
std::unordered_map<std::string, int> mapping {
{"a", 1},
{"b", 2},
{"c", 3}
};
// Destructure by reference.
for (const auto& [key, value] : mapping) {
// Do something with key and value
}
带初始 化 的 选择语句
[编辑]if
{
std::lock_guard<std::mutex> lk(mx);
if (v.empty()) v.push_back(val);
}
// vs.
if (std::lock_guard<std::mutex> lk(mx); v.empty()) {
v.push_back(val);
}
Foo gadget(args);
switch (auto s = gadget.status()) {
case OK: gadget.zip(); break;
case Bad: throw BadFoo(s.message());
}
// vs.
switch (Foo gadget(args); auto s = gadget.status()) {
case OK: gadget.zip(); break;
case Bad: throw BadFoo(s.message());
}
constexpr if
[编辑]//适用场景1:简化模 版 偏 特 化 的 写 法
template <typename T>
constexpr bool isIntegral() {
if constexpr (std::is_integral<T>::value) {
return true;
} else {
return false;
}
}
static_assert(isIntegral<int>() == true);
static_assert(isIntegral<char>() == true);
static_assert(isIntegral<double>() == false);
struct S {};
static_assert(isIntegral<S>() == false);
//适用场景2:编写变参模 版 函数
template<int N, int...Ns>
int Sum()
{
if constexpr(0 == sizeof...(Ns))
return N;
else
return N+Sum<Ns...> ();
}
//使用 场景3:替 代 enable_if。编写模 板 函数 时,经常要 使用 enable_if语句来 进行静 态类型 检查,保 证模板 输入的 类型满足某 种要求
template <typename T>
bool IsOdd(T input){
if constexpr (std::is_integral<T>::value) //
return static_cast<bool>(input % 2);
}
utf8字面 量
[编辑]char x = u8'x';
枚 举类型 变量直接 用 大 括 号 初 始 化
[编辑]enum byte : unsigned char {};
byte b {0}; // OK
byte c {-1}; // ERROR
byte d = byte{1}; // OK
byte e = byte{256}; // ERROR
fallthrough, nodiscard, maybe_unused特性
[编辑]C++17 引入
//fallthrough指示 编译器 直通 一 个switch语句:
switch (n) {
case 1:
// ...
[[fallthrough]]
case 2:
// ...
break;
}
//nodiscard引发一 个警告 ,当 具有 该特性 的 函数 或 类的返 回 值被忽 略 :
[[nodiscard]] bool do_something() {
return is_success; // true for success, false for failure
}
do_something(); // warning: ignoring return value of 'bool do_something()',
// declared with attribute 'nodiscard'
// Only issues a warning when `error_info` is returned by value.
struct [[nodiscard]] error_info {
// ...
};
error_info do_something() {
error_info ei;
// ...
return ei;
}
do_something(); // warning: ignoring returned value of type 'error_info',
// declared with attribute 'nodiscard'
//maybe_unused告 诉编译器变量或 参 数 可能 未 被 使用 :
void my_callback(std::string msg, [[maybe_unused]] bool error) {
// Don't care if `msg` is an error message, just log it.
log(msg);
}
__has_include运算符
[编辑]__has_include运算
//下 例 有 两个相 同 作用 的 头文件 ,如果主文 件 不能 包含 , 就使用 backup/experimental头文件 :
#ifdef __has_include
# if __has_include(<optional>)
# include <optional>
# define have_optional 1
# elif __has_include(<experimental/optional>)
# include <experimental/optional>
# define have_optional 1
# define experimental_optional
# else
# define have_optional 0
# endif
#endif
//也可以用在 不同 位置 、不同 名字 但 具有 相 同 地位 的 头文件 的 包含 :
#ifdef __has_include
# if __has_include(<OpenGL/gl.h>)
# include <OpenGL/gl.h>
# include <OpenGL/glu.h>
# elif __has_include(<GL/gl.h>)
# include <GL/gl.h>
# include <GL/glu.h>
# else
# error No suitable OpenGL headers found.
# endif
#endif
std::variant
[编辑]std::variant
std::variant<int, double> v{ 12 };
std::get<int>(v); // == 12
std::get<0>(v); // == 12
v = 12.0;
std::get<double>(v); // == 12.0
std::get<1>(v); // == 12.0
std::optional
[编辑]std::optional类模
std::optional<std::string> create(bool b) {
if (b) {
return "Godzilla";
} else {
return {};//或 者 return std::nullopt;
}
}
create(false).has_value();//返 回 true或 false
*create(false);//返 回 值;如果无值,则返回 T()
create(false).value_or("empty"); // == "empty"
create(true).value(); // == "Godzilla"
// optional-returning factory functions are usable as conditions of while and if
if (auto str = create(true)) {
// ...
}
std::any
[编辑]std::any
std::any x {5};
x.has_value() // == true
std::any_cast<int>(x) // == 5
std::any_cast<int&>(x) = 10;
std::any_cast<int>(x) // == 10
std::string_view
[编辑]std::string_view类是
// Regular strings.
std::string_view cppstr {"foo"};
// Wide strings.
std::wstring_view wcstr_v {L"baz"};
// Character arrays.
char array[3] = {'b', 'a', 'r'};
std::string_view array_v(array, std::size(array));
std::string str {" trim me"};
std::string_view v {str};
v.remove_prefix(std::min(v.find_first_not_of(" "), v.size()));
str; // == " trim me"
v; // == "trim me"
std::string_view
std::invoke
[编辑]std::invoke
template <typename Callable>
class Proxy {
Callable c;
public:
Proxy(Callable c): c(c) {}
template <class... Args>
decltype(auto) operator()(Args&&... args) {
// ...
return std::invoke(c, std::forward<Args>(args)...);
}
};
auto add = [](int x, int y) {
return x + y;
};
Proxy<decltype(add)> p {add};
p(1, 2); // == 3
std::apply
[编辑]std::apply
auto add = [](int x, int y) {
return x + y;
};
std::apply(add, std::make_tuple(1, 2)); // == 3
std::filesystem
[编辑]std::filesystem
const auto bigFilePath {"bigFileToCopy"};
if (std::filesystem::exists(bigFilePath)) {
const auto bigFileSize {std::filesystem::file_size(bigFilePath)};
std::filesystem::path tmpPath {"/tmp"};
if (std::filesystem::space(tmpPath).available > bigFileSize) {
std::filesystem::create_directory(tmpPath.append("example"));
std::filesystem::copy_file(bigFilePath, tmpPath.append("newFile"));
}
}
std::byte
[编辑]std::byte类型
std::byte a {0};
std::byte b {0xFF};
int i = std::to_integer<int>(b); // 0xFF
std::byte c = a & b;
int j = std::to_integer<int>(c); // 0
maps 和 sets 上 更 有效 率 地 移 动节点
[编辑]//Moving elements from one map to another:
std::map<int, string> src {{1, "one"}, {2, "two"}, {3, "buckle my shoe"}};
std::map<int, string> dst {{3, "three"}};
dst.insert(src.extract(src.find(1))); // Cheap remove and insert of { 1, "one" } from `src` to `dst`.
dst.insert(src.extract(2)); // Cheap remove and insert of { 2, "two" } from `src` to `dst`.
// dst == { { 1, "one" }, { 2, "two" }, { 3, "three" } };
//Inserting an entire set:
std::set<int> src {1, 3, 5};
std::set<int> dst {2, 4, 5};
dst.merge(src);
// src == { 5 }
// dst == { 1, 2, 3, 4, 5 }
//Inserting elements which outlive the container:
auto elementFactory() {
std::set<...> s;
s.emplace(...);
return s.extract(s.begin());
}
s2.insert(elementFactory());
//Changing the key of a map element:
std::map<int, string> m {{1, "one"}, {2, "two"}, {3, "three"}};
auto e = m.extract(2);
e.key() = 4;
m.insert(std::move(e));
// m == { { 1, "one" }, { 3, "three" }, { 4, "two" } }
并行算法
[编辑]许多STL
std::vector<int> longVector;
// Find element using parallel execution policy
auto result1 = std::find(std::execution::par, std::begin(longVector), std::end(longVector), 2);
// Sort elements using sequential execution policy
auto result2 = std::sort(std::execution::seq, std::begin(longVector), std::end(longVector));
注釋
[编辑]- ^ N3928: Extending static_assert, v2 (Walter E. Brown) (PDF). [2015-07-16]. (
原始 内容 存 档 (PDF)于2015-08-11). - ^ N3981: Removing trigraphs??! (Richard Smith). 2014-05-06 [2015-07-16]. (
原始 内容 存 档于2018-07-09). - ^ IBM comment on preparing for a Trigraph-adverse future in C++17 (页面
存 档备份,存 于互联网档案 馆), IBM paper N4210, 2014-10-10. Authors: Michael Wong, Hubert Tong, Rajan Bhakta, Derek Inglis - ^ N4051: Allow typename in a template template parameter (Richard Smith). [2015-07-16]. (
原始 内容 存 档于2015-08-11). - ^ N4259: Wording for std::uncaught_exceptions (Herb Sutter) (PDF). [2015-07-16]. (
原始 内容 (PDF)存 档于2014-11-29). - ^ 6.0 6.1 6.2 New core language papers adopted for C++17. [2015-07-16]. (
原始 内容 存 档于2015-04-27). - ^ N4295: Folding expressions (Andrew Sutton, Richard Smith). [2015-07-16]. (
原始 内容 存 档于2015-04-04). - ^ 8.0 8.1 8.2 New standard library papers adopted for C++17. [2015-07-16]. (
原始 内容 存 档于2014-11-29). - ^ N4280: Non-member size() and more (Riccardo Marcangelo) (PDF). [2015-07-16]. (
原始 内容 存 档 (PDF)于2015-03-09). - ^ N4284: Contiguous Iterators (Jens Maurer). [2015-07-16]. (
原始 内容 存 档于2014-11-29). - ^ Mathematical Special Functions for C++17, v5 (PDF). [2016-08-02]. (
原始 内容 存 档 (PDF)于2016-04-05). - ^ Adopt Library Fundamentals V1 TS Components for C++17 (R1). [2016-08-02]. (
原始 内容 存 档于2016-04-05). - ^ N3922: New Rules for auto deduction from braced-init-list (James Dennett). [2015-07-16]. (
原始 内容 存 档于2015-08-10). - ^ 14.0 14.1 Updates to my trip report. [2015-07-16]. (
原始 内容 存 档于2015-03-19). - ^ N4230: Nested namespace definition (Robert Kawulak, Andrew Tomazos). [2015-07-16]. (
原始 内容 存 档于2015-08-03). - ^ N4267: Adding u8 character literals (Richard Smith). [2015-07-16]. (
原始 内容 存 档于2015-10-28). - ^ std::basic_string_view - cppreference.com. en.cppreference.com. [2016-06-23]. (
原始 内容 存 档于2016-06-17). - ^ Filesystem Library Proposal (Beman Dawes). [2016-08-02]. (
原始 内容 存 档于2016-07-20). - ^ N4279: Improved insertion interface for unique-key maps (Thomas Köppe). [2015-07-16]. (
原始 内容 存 档于2015-04-27). - ^ The Parallelism TS Should be Standardized. [2016-08-02]. (
原始 内容 存 档于2016-04-05).
另見
[编辑]
|