c++14概述
2026/5/3 22:40:40 网站建设 项目流程

C++14

概述

C++14 包含以下新的语言特性:

  • 二进制字面量
  • 通用 lambda 表达式
  • lambda 捕获初始化器
  • 返回类型推导
  • decltype(auto)
  • 放宽 constexpr 函数的约束
  • 变量模板
  • [[deprecated]] 属性

C++14 包含以下新的库特性:

  • 标准库类型的用户自定义字面量
  • 编译期整数序列
  • std::make_unique

C++14 语言特性

二进制字面量

二进制字面量提供了一种便捷的方式来表示二进制(基数为2)数字,还可以使用'分隔数字位以提升可读性。

0b110 // 等于 6 0b1111'1111 // 等于 255

通用 lambda 表达式

C++14 允许在 lambda 表达式的参数列表中使用auto类型说明符,从而支持多态 lambda。

auto identity = [](auto x) { return x; }; int three = identity(3); // 等于 3 std::string foo = identity("foo"); // 等于 "foo"

lambda 捕获初始化器

该特性允许使用任意表达式初始化 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_unique<int>(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

返回类型推导

在 C++14 中使用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_same<const int&, decltype(f(x))>::value == 0); static_assert(std::is_same<int, decltype(f(x))>::value == 1); static_assert(std::is_same<const int&, decltype(g(x))>::value == 1);

另见:decltype (C++11)

放宽 constexpr 函数的约束

在 C++11 中,constexpr函数体仅能包含有限的语法,包括(但不限于):typedefusing以及单个return语句。C++14 大幅扩展了允许的语法范围,支持最常用的语法,如if语句、多个return语句、循环等。

constexpr int factorial(int n) { if (n <= 1) { return 1; } else { return n * factorial(n - 1); } } factorial(5); // 等于 120

变量模板

C++14 允许对变量进行模板化:

template<class T> constexpr T pi = T(3.1415926535897932385); template<class T> constexpr T e = T(2.7182818284590452353);

[[deprecated]] 属性

C++14 引入[[deprecated]]属性,用于标记不建议使用的单元(函数、类等),使用这类单元通常会触发编译警告。若指定了原因,该原因会包含在警告信息中。

[[deprecated]] void old_method(); [[deprecated("请改用 new_method")]] void legacy_method();

C++14 库特性

标准库类型的用户自定义字面量

为标准库类型新增了用户自定义字面量,包括针对chronobasic_string的新内置字面量。这些字面量可以是constexpr,意味着它们能在编译期使用。这类字面量的用途包括编译期整数解析、二进制字面量以及虚数字面量等。

using namespace std::chrono_literals; auto day = 24h; day.count(); // 等于 24 std::chrono::duration_cast<std::chrono::minutes>(day).count(); // 等于 1440

编译期整数序列

类模板std::integer_sequence表示一个编译期整数序列。基于它实现了一些辅助工具:

  • std::make_integer_sequence<T, N>- 创建类型为T、包含0, ..., N - 1的序列。
  • std::index_sequence_for<T...>- 将模板参数包转换为整数序列。

示例:将数组转换为元组

template<typename Array, std::size_t... I> decltype(auto) a2t_impl(const Array& a, std::integer_sequence<std::size_t, I...>) { return std::make_tuple(a[I]...); } template<typename T, std::size_t N, typename Indices = std::make_index_sequence<N>> decltype(auto) a2t(const std::array<T, N>& a) { return a2t_impl(a, Indices()); }

std::make_unique

std::make_unique是创建std::unique_ptr实例的推荐方式,原因如下:

  • 避免手动使用new运算符。
  • 避免指定指针持有的底层类型时重复代码。
  • 最重要的是,它提供异常安全性。例如,假设我们像这样调用函数foo
foo(std::unique_ptr<T>{new T{}}, function_that_throws(), std::unique_ptr<T>{new T{}});

编译器可能会先调用new T{},再调用function_that_throws(),以此类推……由于我们在第一个T的构造过程中在堆上分配了内存,此处会引入内存泄漏。使用std::make_unique则能保证异常安全:

foo(std::make_unique<T>(), function_that_throws(), std::make_unique<T>());

关于std::unique_ptrstd::shared_ptr的更多信息,参见智能指针 (C++11) 部分。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询