C++14
语言特性
二进制字面量
二进制字面量提供了一种方便的方式来表示二进制数字。可以用’分隔数字。
0b110 // == 6
0b1111'1111 // == 255
通用 lambda 表达式
C++14 现在允许在参数列表中使用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 {
// 这不会在没有“mutalbe”的情况下编译,因为我们在每次调用时都修改 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无法被复制
// vs.
auto task2 = [p = std::move(p)] { *p = 5; }; // OK: p 被移动构造成闭包对象
// 创建 task2 后原始 p 为空
使用此引用捕获可以具有与引用变量不同的名称。
auto x = 1;
auto f = [&r = x, x = x * 10] {
++r;
return r + x;
};
f(); // sets x to 2 and returns 12
返回类型推导
在 C++14 中使用自动返回类型,编译器将尝试为您推断类型。使用 lambdas,您现在可以使用 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限定符的同时推断返回类型,而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);
放宽对 constexpr 函数的约束
在 C++11 中,constexpr
函数体只能包含一组非常有限的语法,包括(但不限于):typedef
、using
和单个return
语句。在 C++14 中,允许的语法集大大扩展,包括最常见的语法,例如if
语句、多个返回、循环等。
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("Use new_method instead")]]
void legacy_method();
标准库
标准库类型的用户定义字面量
标准库类型的新用户定义字面量,包括chrono
和basic_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
实例的推荐方法