文章目录
- 1、lambda表达式
- 2、constexpr关键字
- 3、函数返回类型推导
- 4、变量模版
- 5、二进制字面值
- 6、数字分位符
- 7、通过类型寻址多元组
- 8、make_unique
1、lambda表达式
C++14提供了在lambda式的形参声明中使用auto的能力
泛型 lambda:C++14 中的 lambda 表达式可以使用模板参数,使其成为一个泛型函数对象。这样可以实现更加通用的操作。例如:
auto print = [](auto value) {
std::cout << value << std::endl;
};
print(10); // 输出:10
print("Hello"); // 输出:Hello
泛型 lambda 函数遵循模板参数推导的规则。以上代码的作用与下面的代码相同:
struct unnamed_lambda
{
template<typename T, typename U>
auto operator()(T x, U y) const {return x + y;}
};
auto lambda = unnamed_lambda();
lambda 捕获表达式(在lambda初始列表中使用表达式):
C++11 的 lambda 函数通过值拷贝或引用捕获已在外层作用域声明的变量。这意味着 lambda 的值成员是不可以move的。C++14允许被捕获的成员用任意的表达式初始化。这既允许了move,也允许了任意声明 lambda 的成员,而不需要外层作用域有一个具有相应名字的变量。
这是通过使用一个初始化表达式完成的:
auto lambda = [value = 1] {return value;};
lambda 函数 lambda 的返回值是 1,说明 value 被初始化为 1。被声明的捕获变量的类型会根据初始化表达式推断,推断方式与用 auto 声明变量相同。
初始化列表可以使用move来移动外部变量:
auto ptr = std::make_unique<int>(10);
auto lambda = [ptr = std::move(ptr)]{ return *ptr; };
constexpr lambda:C++14 中的 lambda 表达式可以被声明为 constexpr,表示它是一个编译时常量表达式。这样可以在编译时进行求值,并用于需要常量表达式的场景。例如:
constexpr auto square = [](int x) constexpr {
return x * x;
};
constexpr int result = square(5); // 在编译时计算出结果 25
2、constexpr关键字
C++14 对 constexpr 关键字进行了一些扩展,使其能够应用于更多的情况。
放宽了对函数的限制:在 C++11 中,constexpr 函数的函数体只能有using 指令、typedef 语句、static_assert 断言、空语句,只能有一条return 语句,并且该语句必须是常量表达式。而在 C++14 中,constexpr 函数可以包含多条语句,可以有条件语句(如 if)和循环语句(如 for、while),只要在编译时能够被求值为常量表达式即可。例如:
constexpr int factorial(int n) {
int result = 1;
for (int i = 1; i <= n; ++i) {
result *= i;
}
return result;
}
constexpr int result = factorial(5); // 在编译时计算出结果 120
3、函数返回类型推导
lambda表达式可以使用auto形参和返回类型,但普通函数不能使用auto形参。
虽然普通函数不能使用auto形参,但可以使用返回类型推导。在C++11中我们可以使用后置返回类型推导来完成这件事情:
//C++11中使用后置返回类型推导
auto add(int x, int y) ->decltype(x + y)
{
return x + y;
}
而在C++14中,我们可以省略decltype,编译器直接由return语句的值推导出返回类型:
auto add(int x, int y)
{
return x + y;
}
如果函数实现中含有多个 return 语句,这些表达式必须可以推断为相同的类型
auto PI(bool fract)
{
if (fract) return 3.1416;
else return 3; //错误:推导出来的int与之前推导出来的double冲突
}
对于含有递归调用的函数,递归调用必须在第一个return之后
auto Correct(int i)
{
if (i == 1)
return i; // 返回类型被推断为 int
else
return Correct(i-1)+i; // 正确,可以调用
}
auto Wrong(int i)
{
if(i != 1)
return Wrong(i-1)+i; // 不能调用,之前没有 return 语句
else
return i; // 返回类型被推断为 int
}
4、变量模版
C++14中,引入了一种称为变量模板的新的模板类型
#include <iostream>
#include <iomanip>
using namespace std;
// 函数模板
template<class T>
constexpr T pi_fn()
{
return T(3.1415926535897932385);
}
// 变量模板
template<class T>
constexpr T pi = T(3.1415926535897932385);
int main()
{
cout << pi_fn<int>() << pi<int> << '\n'; // 33
cout << setprecision(10) << pi<float> << '\n'; // 3.141592741
cout << setprecision(10) << pi<double> << '\n'; // 3.141592654
}
5、二进制字面值
二进制字面值可以使用0b或者0B开头来表示
int i = 0b0100010001; // 273
int i = 0B0100010001; // 273,大写B
6、数字分位符
C++14 引入单引号(’)作为数字分位符号,使得数值型的字面量可以具有更好的可读性
auto integer_literal = 100'0000;
auto floating_point_literal = 1.797'693'134'862'315'7E+308;
auto binary_literal = 0b0100'1100'0110;
auto silly_example = 1'0'0'000'00;
7、通过类型寻址多元组
C++11 引入的 std::tuple 类型允许不同类型的值的聚合体用编译期整型常数索引。C++14还允许使用类型代替常数索引,从多元组中获取对象。若多元组含有多于一个这个类型的对象,将会产生一个编译错误:
tuple<string, string, int> t("foo", "bar", 7);
int i = get<int>(t); // i == 7
int j = get<2>(t); // Same as before: j == 7
string s = get<string>(t); //Compiler error due to ambiguity
8、make_unique
std::make_unique 可以像 std::make_shared 一样使用,用于产生 std::unique_ptr 对象
std::unique_ptr<int> ptr = std::make_unique<int>(42);