C++ 14新特性个人总结

在这里插入图片描述

variable templates

变量模板。这个特性允许模板被用于定义变量,就像之前模板可以用于定义函数或类型一样。变量模板为模板编程带来了新的灵活性,特别是在定义泛化的常量和元编程时非常有用。
在这里插入图片描述

变量模板的基本语法

变量模板的声明遵循以下基本语法:

template<typename T>
constexpr T someValue = /* some value depending on T */;

这里,T是一个类型参数,someValue是根据T变化的一个变量。

示例:定义一个泛化的π值

考虑一个简单的例子,我们想要定义一个依据类型变化的π值,以便能够获取不同精度的π值(例如,floatdoublelong double等)。

#include <iostream>

template<typename T>
constexpr T pi = T(3.1415926535897932385);

int main() {
   
    std::cout << "pi<float> = " << pi<float> << std::endl;
    std::cout << "pi<double> = " << pi<double> << std::endl;
    std::cout << "pi<long double> = " << pi<long double> << std::endl;

    return 0;
}

这个例子中,我们定义了一个变量模板pi,其类型是模板参数T。因此,我们可以请求pi的不同类型版本,获取相应精度的π值。

注意事项

  • 类型完整性:变量模板在实例化时要求其类型参数必须是完整类型。
  • 模板参数限制:和函数或类模板一样,变量模板不能推导其模板参数。

generic lambdas

泛型Lambda表达式,这大大增强了Lambda的灵活性和通用性。泛型Lambda允许Lambda的参数类型自动推导,更重要的是,它允许Lambda使用模板参数。这意味着,你可以写出更为通用的Lambda表达式,它们能够处理多种不同类型的数据,而不需要为每种类型编写特定的代码。
在这里插入图片描述

泛型Lambda的基本用法

在C++11中,Lambda参数的类型必须是显式声明的。而在C++14中,你可以使用auto关键字,让编译器自动推导参数的类型。这不仅仅是一个简化的语法糖,它实际上隐式地将Lambda转换成了一个模板。

例如,一个可以比较两个值的Lambda在C++14中可以写成:

auto compare = [](auto a, auto b) {
   
    return a < b;
};

这个Lambda可以用于比较任意两个可以进行<操作的类型的值。

实现原理

当编译器遇到泛型Lambda的时候,它实际上为Lambda自动生成了一个模板类。每次调用泛型Lambda时,编译器根据传递给Lambda的参数类型,实例化出一个特定的模板实例。这就是C++14泛型Lambda如何提供类型通用性的基本原理。

使用场景

泛型Lambda可以在很多场合下简化代码,特别是与STL算法一起使用时。例如,使用泛型Lambda在一个容器中查找一个元素:

std::vector<int> v = {
   1, 2, 3, 4, 5};
int to_find = 3;
auto found = std::find_if(v.begin(), v.end(), [to_find](auto elem) {
    return elem == to_find; });

这段代码使用了泛型Lambda来定义查找条件,这使得相同的Lambda可以应用于不同类型的容器和元素。

注意事项

  • 捕获表达式的自动类型推导:泛型Lambda可以捕获外部变量,但是这些捕获的变量类型必须在Lambda表达式创建时就已经确定。这意味着不能捕获泛型Lambda自身作为变量,因为在创建时Lambda的类型还未确定。

  • Lambda不能被重载或特化:与函数模板不同,Lambda表达式不能被重载或特化。这意味着同一个Lambda表达式必须能够处理所有它可能被调用的的类型。

  • 递归调用:泛型Lambda表达式不能直接递归调用自己,因为auto类型参数不允许在Lambda内部推导其自身类型

lambda init-capture

C++14引入了一个新的Lambda表达式特性:初始化捕获(init-capture),也被称为广义Lambda捕获或Lambda初始化。这项特性让我们能够在Lambda表达式的捕获列表中,直接定义并初始化新的变量。这提供了更加灵活的变量捕获方式,允许在Lambda表达式创建时构造新的对象或执行复杂的初始化。
在这里插入图片描述

基本语法

初始化捕获的基本语法是在Lambda捕获列表中使用[name = expression]形式,其中name是在Lambda体中使用的新变量的名称,而expression是用于初始化该变量的表达式。例如:

int x = 42;
auto lambda = [y = x + 1] {
    return y; };
std::cout << lambda(); // 输出 43

在这个例子中,通过初始化捕获创建了一个名为y的新变量,并将其初始化为x + 1的值。y在Lambda内部可用,就像任何其他捕获的变量一样。

特点与用途

初始化捕获的引入解决了C++11中存在的一些局限性:

  • 移动语义支持:在C++11中,Lambda只能通过值或引用捕获外部变量,不能方便地捕获通过移动语义获得的对象。C++14通过初始化捕获支持移动语义,使得能够移动而非复制对象到Lambda表达式内部。

    auto p = std::make_unique<int>(42);
    auto lambda = [ptr = std::move(p)] {
          return *ptr; };
    
  • 复杂的初始化:初始化捕获允许在Lambda捕获列表中执行复杂的表达式计算,无需在Lambda外部单独声明和初始化变量。

  • 避免不必要的捕获:有时我们希望Lambda表达式依赖于从外部变量派生的值,而不直接依赖这些外部变量本身。通过初始化捕获,可以避免不必要地捕获外部变量,减少资源捕获的开销。

注意事项

  • 初始化捕获只能创建拷贝或通过移动语义创建的变量。这意味着,你不能通过初始化捕获来直接声明一个引用类型的变量。例如,以下代码是不合法的:
int x = 42;
auto lambda = [&y = x] {
    return y; }; // 错误:不能通过初始化捕获来创建引用

relaxed restrictions on constexpr functions

在C++14中,对constexpr函数的限制相较于C++11有了显著放宽。constexpr函数或变量表达的是它们可以在编译时被求值,这对于提高程序的性能和安全性非常重要。在C++11中,标记为constexpr的函数受到了很多限制,使得它们的用途相对有限。然而,C++14放宽了这些限制,使得constexpr函数变得更加灵活和强大。

C++11中的constexpr函数限制包括:

  • 函数体内只能包含一个单一的返回语句。
  • 不能有任何变量声明。
  • 不能有任何循环或分支语句。

C++14放宽的限制:

  1. 多条语句:C++14允许constexpr函数包含多条语句,使得你可以在constexpr函数中执行更复杂的计算。

  2. 局部变量:允许在constexpr函数内部声明和使用局部变量,只要这些变量的类型也都是字面类型(Literal Type)。

  3. 循环和分支:在C++14中,constexpr函数现在可以使用循环和条件分支,这大大增加了它们的灵活性和能力。

  4. 递归:由于允许使用多条语句和条件分支,constexpr函数现在也支持递归调用。

示例对比:

C++11中的constexpr函数:

constexpr int factorial(int n) {
   
    return n <= 1 ? 1 : (n * factorial(n - 1));
}

C++14中的constexpr函数:

constexpr int factorial(int n) {
   
    int result = 1;
    for(int i = 1; i <= n; ++i) {
   
        result *= i;
    }
    return result;
}

在C++14的例子中,我们利用了局部变量、循环,以及允许在constexpr函数中包含多条语句的特性。

注意点:

  • 即使C++14放宽了对constexpr函数的限制,但是为了在编译时求值,函数的所有输入和逻辑仍然需要在编译时是已知的。
  • constexpr函数也可以在运行时被调用,如果其参数在编译时不是已知的。在这种情况下,它们就像普通函数那样工作。

binary literals

二进制字面量,使得开发者可以直接在代码中以二进制形式表示整数。这一特性对于底层编程、位操作或者对内存布局有特定要求的场景尤为有用。在C++14之前,表达二进制数据通常需要使用十六进制或八进制,尽管这些方法也相对直观,但直接使用二进制字面量无疑能让代码的意图更加明显。
在这里插入图片描述

使用方法

二进制字面量通过在数字前加0b0B前缀来表示。后续紧跟二进制数字(0或1)。


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值