C14概述C14 包含以下新的语言特性二进制字面量通用 lambda 表达式lambda 捕获初始化器返回类型推导decltype(auto)放宽 constexpr 函数的约束变量模板[[deprecated]] 属性C14 包含以下新的库特性标准库类型的用户自定义字面量编译期整数序列std::make_uniqueC14 语言特性二进制字面量二进制字面量提供了一种便捷的方式来表示二进制基数为2数字还可以使用分隔数字位以提升可读性。0b110 // 等于 6 0b11111111 // 等于 255通用 lambda 表达式C14 允许在 lambda 表达式的参数列表中使用auto类型说明符从而支持多态 lambda。auto identity [](auto x) { return x; }; int three identity(3); // 等于 3 std::string foo identity(foo); // 等于 foolambda 捕获初始化器该特性允许使用任意表达式初始化 lambda 捕获的变量。捕获值的命名无需与外围作用域中的变量相关联且会在 lambda 体内部引入一个新名称。初始化表达式在 lambda创建而非调用时求值。int factory(int i) { return i * 10; } auto f [x factory(2)] { return x; }; // 返回 20 auto generator [x 0] () mutable { // 如果没有 mutable此代码无法编译因为每次调用都会修改 x return x; }; auto a generator(); // 等于 0 auto b generator(); // 等于 1 auto c generator(); // 等于 2此前lambda 仅能通过拷贝或引用捕获变量现在则可以将值移动或转发到 lambda 中因此能够按值捕获仅可移动类型。注意下述示例中task2捕获列表里左侧的p是 lambda 体私有的新变量与原p无关。auto p std::make_uniqueint(1); auto task1 [] { *p 5; }; // 错误std::unique_ptr 无法拷贝 // 对比 auto task2 [p std::move(p)] { *p 5; }; // 正确p 被移动构造到闭包对象中 // 创建 task2 后原 p 变为空通过该特性引用捕获的变量可以使用与原变量不同的名称。auto x 1; auto f [r x, x x * 10] { r; return r x; }; f(); // 将 x 设为 2并返回 12返回类型推导在 C14 中使用auto作为返回类型时编译器会尝试为你推导具体类型。对于 lambda 表达式现在也可以通过auto推导其返回类型这使得返回推导所得的引用或右值引用成为可能。// 推导返回类型为 int。 auto f(int i) { return i; }template typename T auto f(T t) { return t; } // 返回推导类型的引用。 auto g [](auto x) - auto { return f(x); }; int y 123; int z g(y); // 指向 y 的引用decltype(auto)decltype(auto)类型说明符与auto一样会推导类型但它在推导返回类型时会保留引用和 cv 限定符const/volatile而auto不会。const int x 0; auto x1 x; // int decltype(auto) x2 x; // const int int y 0; int y1 y; auto y2 y1; // int decltype(auto) y3 y1; // int int z 0; auto z1 std::move(z); // int decltype(auto) z2 std::move(z); // int// 注意在泛型代码中尤其有用 // 返回类型为 int。 auto f(const int i) { return i; } // 返回类型为 const int。 decltype(auto) g(const int i) { return i; } int x 123; static_assert(std::is_sameconst int, decltype(f(x))::value 0); static_assert(std::is_sameint, decltype(f(x))::value 1); static_assert(std::is_sameconst int, decltype(g(x))::value 1);另见decltype (C11)。放宽 constexpr 函数的约束在 C11 中constexpr函数体仅能包含有限的语法包括但不限于typedef、using以及单个return语句。C14 大幅扩展了允许的语法范围支持最常用的语法如if语句、多个return语句、循环等。constexpr int factorial(int n) { if (n 1) { return 1; } else { return n * factorial(n - 1); } } factorial(5); // 等于 120变量模板C14 允许对变量进行模板化templateclass T constexpr T pi T(3.1415926535897932385); templateclass T constexpr T e T(2.7182818284590452353);[[deprecated]] 属性C14 引入[[deprecated]]属性用于标记不建议使用的单元函数、类等使用这类单元通常会触发编译警告。若指定了原因该原因会包含在警告信息中。[[deprecated]] void old_method(); [[deprecated(请改用 new_method)]] void legacy_method();C14 库特性标准库类型的用户自定义字面量为标准库类型新增了用户自定义字面量包括针对chrono和basic_string的新内置字面量。这些字面量可以是constexpr意味着它们能在编译期使用。这类字面量的用途包括编译期整数解析、二进制字面量以及虚数字面量等。using namespace std::chrono_literals; auto day 24h; day.count(); // 等于 24 std::chrono::duration_caststd::chrono::minutes(day).count(); // 等于 1440编译期整数序列类模板std::integer_sequence表示一个编译期整数序列。基于它实现了一些辅助工具std::make_integer_sequenceT, N- 创建类型为T、包含0, ..., N - 1的序列。std::index_sequence_forT...- 将模板参数包转换为整数序列。示例将数组转换为元组templatetypename Array, std::size_t... I decltype(auto) a2t_impl(const Array a, std::integer_sequencestd::size_t, I...) { return std::make_tuple(a[I]...); } templatetypename T, std::size_t N, typename Indices std::make_index_sequenceN decltype(auto) a2t(const std::arrayT, N a) { return a2t_impl(a, Indices()); }std::make_uniquestd::make_unique是创建std::unique_ptr实例的推荐方式原因如下避免手动使用new运算符。避免指定指针持有的底层类型时重复代码。最重要的是它提供异常安全性。例如假设我们像这样调用函数foofoo(std::unique_ptrT{new T{}}, function_that_throws(), std::unique_ptrT{new T{}});编译器可能会先调用new T{}再调用function_that_throws()以此类推……由于我们在第一个T的构造过程中在堆上分配了内存此处会引入内存泄漏。使用std::make_unique则能保证异常安全foo(std::make_uniqueT(), function_that_throws(), std::make_uniqueT());关于std::unique_ptr和std::shared_ptr的更多信息参见智能指针 (C11) 部分。