【翻译】C++14的新特性简介
之前写完了《C++Primer》的笔记,但是《C++Primer》已经是快十年的老书了,其包含的C++特性仅仅到C11为止,因此又去看了些C++14的特性,发现Anthony Calandra在https://github.com/AnthonyCalandra/modern-cpp-features/blob/master/CPP14.md 中有对C++14重要的新特性的简介,看完就翻译整理后发上来了。原文中有些地方写得不是很好理解所以对其做了少量修改。
新特性一览
语言新特性
- 二进制字面值
- 泛型的Lambda表达式
- 初始化Lambda的捕获列表
- 推断返回类型
- decltype(auto)
- 放宽对常量表达式函数的约束
- 变量模板
- [[deprecated]]属性
标准库新特性
- 可用于标准库类型的自定义字面量
- 编译期的整型序列
- std::make_unique
二进制字面值(Binary literals)
二进制字面值提供了一个表示二进制数字的方便的方法,有了这个之后我们可以直接使用二进制数字了,而且允许我们使用单引号 ' 来作为数字分位符让数字方便阅读
0b110 // == 6
0b1111'1111 // == 255
泛型的Lambda表达式(Generic lambda expressions)
C14允许我们在Lambda的参数列表中使用auto了,使多态的Lambda成为可能
auto identity = [](auto x) { return x; };
int three = identity(3); // == 3
std::string foo = identity("foo"); // == "foo"
初始化Lambda的捕获列表(Lambda capture initializers)
C14允许我们用任意的表达式对Lambda的捕获列表内容进行初始化了。如今提供给捕获列表的名称不再需要与任何所在的局部范围的变量相关联了,而且可以向Lambda表达式输入引入新的名称了。初始化表达式会在Lambda被创建时(而不是调用时)进行计算
int factory(int i) { return i * 10; }
auto f = [x = factory(2)] { return x; }; // returns 20
auto generator = [x = 0] () mutable {
// this would not compile without 'mutable' as we are modifying x on each call
return x++;
};
auto a = generator(); // == 0
auto b = generator(); // == 1
auto c = generator(); // == 2
于是现在我们可以move()或者forward()那些之前只能通过拷贝或引用捕获的值进入Lambda,因此我们可以捕获那些只允许move的得到右值引用的类型的值进入Lambda了(例如unique_ptr)。注意在下面的例子中等号左边的task2捕获列表中的p是属于Lambda体私有的变量而不是原始p的引用
auto p = std::make_unique<int>(1);
auto task1 = [=] { *p = 5; }; // ERROR: std::unique_ptr cannot be copied
// vs.
auto task2 = [p = std::move(p)] { *p = 5; }; // OK: p is move-constructed into the closure object
// the original p is empty after task2 is created
运用这个引用捕获,我们可以拥有不同于被引用变量的名称
auto x = 1;
auto f = [&r = x, x = x * 10] {
++r;
return r + x;
};
f(); // sets x to 2 and returns 12
推断返回类型(Return type deduction)
编译器会帮你尝试推断出使用auto在C14中作为的返回类型。伴随着Lambda你现在可使用auto减少对其返回类型的描述(不再需要使用尾置返回),这还会使得返回一个推断类型或一个右值引用成为可能
// Deduce return type as `int`.
auto f(int i) {
return i;
}
template <typename T>
auto& f(T& t) {
return t;
}
// Returns a reference to a deduced type.
auto g = [](auto& x) -> auto& { return f(x); };
int y = 123;
int& z = g(y); // reference to `y`
decltype(auto)
decltype(auto)类型说明符也可以像auto一样推断类型。但是,它在推断返回类型的时候能保持它们的引用属性和const属性,这是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&&
// Note: Especially useful for generic code!
// Return type is `int`.
auto f(const int& i) {
return i;
}
// Return type is `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);
放宽对常量表达式函数的约束(Relaxing constraints on constexpr functions)
在C11中,常量表达式函数的函数体只能包含非常局限的语法,包括但不仅仅是: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
变量模板(Variable templates)
C14允许我们编写变量模板如下
template<class T>
constexpr T pi = T(3.1415926535897932385);
template<class T>
constexpr T e = T(2.7182818284590452353);
[[deprecated]]属性 ( [[deprecated]] attribute )
C14引入了[[deprecated]](不推荐)属性,标识了一个元素(函数,类等等…)是不被鼓励且可能引发编译器警告的。如果这个属性包含了一个警告原因,那么这会在编译器警告中显示出来
[[deprecated]]
void old_method();
[[deprecated("Use new_method instead")]]
void legacy_method();
可用于标准库类型的自定义字面量(User-defined literals for standard library types)
新的可用于标准库类型的自定义字面量包括了新的内置字面量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
编译期的整型序列(Compile-time integer sequences)
模板类std::integer_sequence代表了一个串编译期的整型。这里有两个帮助模板类:
- std::make_integer_sequence<T, N> ——创建一个T类型的值从0到N-1的整型序列
- std::index_sequence_for<T...> ——将模板参数的值打包到一个整型序列中
将一个数组转为tuple:
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_shared,C14引入了std::make_unique.由于以下几点原因std::make_unique是创建std::unique_ptr实例的推荐方式:
- 能避免使用到new运算符
- 当要求指针保持基础类型时避免代码的重复
- 最重要的,它是异常安全(exception-safety)的。假如我们用以下方法调用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>());
- 利用TensorFlow生成图像标题
- 保存并加载您的Keras深度学习模型
- 简单、通用的JQuery Tab实现
- Dubbo源码解析 - 远程暴露
- 使用FastText(Facebook的NLP库)进行文本分类和word representatio...
- 声音分类的迁移学习
- 【死磕Java并发】—– J.U.C之AQS:CLH同步队列
- 使用Python完成你的第一个学习项目
- CA,给了数据库,给了机器,为啥也扩不了容?
- 如何使用Anaconda设置机器学习和深度学习的Python环境
- MQ,互联网架构解耦神器
- 预测随机机器学习算法实验的重复次数
- 服务化了,没想到耦合更加严重?
- 如何在Python中扩展LSTM网络的数据
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- django-Views之装饰器(四)
- django-Views之使用视图渲染模板(五)
- springmvc实例之显示雇员相关信息(一)
- django-Views之类视图 (六)
- springmvc之重定向
- django-模板之自定义模板路径(一)
- spring配置Bean之基于xml文件的方式
- django-模板之模板变量(二)
- 【猫狗数据集】计算数据集的平均值和方差
- django-模板之extends(三)
- django-模板之block(四)
- spring之添加后置处理器的bean的生命周期
- django-模板之URL标签(五)
- 【猫狗数据集】读取数据集的第二种方式
- django-模板之comment标签(六)