C++ 14新特性

C++14在C++11的基础上进一步扩展和优化,带来了不少新特性,以下是一些主要的方面:

1. 变量模板

  • 概念与作用:变量模板允许定义模板化的变量,就像函数模板可以根据不同类型生成不同的函数一样,变量模板可以依据不同类型生成不同的变量实例。这使得代码能够以更通用、更灵活的方式处理各种类型相关的数据,尤其在编写泛型代码时非常有用。
  • 示例代码
template<typename T>
constexpr T pi = T(3.1415926535897932385);

int main() {
    std::cout << "int类型的pi值: " << pi<int> << std::endl;
    std::cout << "double类型的pi值: " << pi<double> << std::endl;
    return 0;
}

在上述代码中,定义了一个变量模板 pi,根据传入的不同类型 T,可以生成对应类型的 pi 值。在 main 函数中,分别实例化了 int 类型和 double 类型的 pi,展示了变量模板能方便地针对不同类型提供相应常量值的特性。

2. 泛型 lambda 表达式

  • 概念与作用:C++11 中引入了 lambda 表达式,方便在代码中就地定义匿名函数,但 C++11 的 lambda 表达式在处理泛型方面比较受限。C++14 增强了这一特性,允许 lambda 表达式使用 auto 类型说明符来进行参数类型推导,使其具有了泛型的能力,这样的 lambda 可以像模板函数一样适用于多种不同类型的参数,增强了代码的简洁性和通用性。
  • 示例代码
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {1, 3, 2, 4};
    std::vector<double> dvec = {1.1, 3.3, 2.2, 4.4};

    // 使用泛型lambda表达式对整数向量进行排序
    std::sort(vec.begin(), vec.end(), [](auto a, auto b) { return a < b; });
    // 使用相同的泛型lambda表达式对双精度向量进行排序
    std::sort(dvec.begin(), dvec.end(), [](auto a, auto b) { return a < b; });

    for (int num : vec) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    for (double num : dvec) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    return 0;
}

这里定义的 lambda 表达式 [](auto a, auto b) { return a < b; } 能够自动根据传入的参数类型(无论是 int 还是 double 等)进行类型推导并执行相应的比较操作,无需为不同类型的容器编写多个特定类型的排序 lambda 表达式,提高了代码复用性。

3. 返回类型推导的扩展

  • 概念与作用:C++11 就开始支持函数返回类型推导,但有一定限制,例如函数体中必须是单一的 return 语句等情况才能方便地使用返回类型推导。C++14 放宽了这些限制,使得更多函数可以利用返回类型推导功能,即使函数体中有多个语句、复杂的控制流等情况,只要最终能明确推导出返回类型,都可以使用该特性,进一步简化了代码编写,尤其是对于一些复杂的泛型函数等场景。
  • 示例代码
#include <iostream>

// 一个简单的函数,根据条件返回不同类型的值,利用C++14扩展的返回类型推导
auto get_value(bool condition) {
    if (condition) {
        return 5;  // 可以推导出返回类型为int
    } else {
        return 3.14;  // 也可以推导出返回类型为double
    }
}

int main() {
    std::cout << get_value(true) << std::endl;
    std::cout << get_value(false) << std::endl;
    return 0;
}

get_value 函数中,根据传入的布尔值条件返回不同类型的值,C++14 能够正确推导出返回类型,使得编写这样的函数更加简洁,无需显式指定返回类型(当然,前提是编译器能根据代码逻辑明确推导出类型)。

4. 二进制字面量

  • 概念与作用:在以往的C++代码中,如果要表示二进制数,通常需要先将其转换为十六进制或八进制等形式,再进行赋值等操作,不够直观。C++14 引入了二进制字面量的表示方法,允许直接使用 0b0B 前缀来表示二进制数,这使得在处理与二进制相关的数据(比如位操作、底层硬件交互等场景)时更加清晰、便捷。
  • 示例代码
int main() {
    int num = 0b1010;  // 直接用二进制字面量表示十进制的10
    std::cout << "二进制1010对应的十进制数: " << num << std::endl;
    return 0;
}

通过 0b1010 这种形式直观地表示了一个二进制数,编译器会将其转换为对应的十进制数值(这里是10),方便了对二进制数据的书写和操作。

5. 数字分隔符

  • 概念与作用:对于较长的数字字面量(如大整数、浮点数等),为了提高其可读性,C++14 允许使用单引号(')作为数字分隔符,将数字按一定逻辑进行分隔,使其更易于理解和查看,同时又不影响数字本身的数值含义。
  • 示例代码
int main() {
    long long big_num = 123'456'789'012'345;  // 使用数字分隔符表示一个大整数
    double big_float = 1.234'567'89;  // 对浮点数也可以使用数字分隔符
    std::cout << "大整数: " << big_num << std::endl;
    std::cout << "大浮点数: " << big_float << std::endl;
    return 0;
}

在上述代码中,通过数字分隔符把长数字进行了合理划分,使其在代码中更直观地展示数值大小,方便阅读和代码维护,尤其是在处理金融、科学计算等涉及到大数值的领域很有帮助。

6. 函数对象的改进

  • constexpr 函数对象:C++14 允许用户自定义的函数对象(例如重载了 operator() 的类)可以标记为 constexpr,意味着这样的函数对象可以在编译期执行,用于在编译阶段计算一些常量表达式,这对于优化性能、提高代码的灵活性以及在模板元编程等场景下有很大的作用。
  • 示例代码
#include <iostream>

class Add {
public:
    constexpr int operator()(int a, int b) const {
        return a + b;
    }
};

int main() {
    constexpr Add add_obj;
    constexpr int result = add_obj(3, 5);  // 在编译期就能计算出结果
    std::cout << "编译期计算结果: " << result << std::endl;
    return 0;
}

这里定义的 Add 类作为函数对象,其 operator() 被标记为 constexpr,所以在 main 函数中可以在编译期就计算出 3 + 5 的结果,并且将其作为常量表达式使用,这在一些对性能和编译期计算有要求的场景中非常有用。

7. 聚合初始化的扩展

  • 概念与作用:在C++中,聚合初始化是一种方便的初始化对象的方式,C++14 对其进行了扩展,使得在初始化聚合体(如结构体、数组等)时更加灵活,减少了一些之前需要遵循的严格限制,比如可以使用花括号初始化包含继承关系的聚合类对象等,让代码编写更加简洁自然。
  • 示例代码
#include <iostream>

struct Base {
    int base_num;
};

struct Derived : public Base {
    int derived_num;
};

int main() {
    // 使用扩展的聚合初始化方式初始化派生类对象
    Derived d = {1, 2};
    std::cout << "Base成员值: " << d.base_num << ", Derived成员值: " << d.derived_num << std::endl;
    return 0;
}

在这个例子中,通过 {1, 2} 这种简单的花括号初始化方式就可以对包含继承关系的 Derived 类对象进行初始化,编译器会按照相应顺序(先初始化基类成员,再初始化派生类成员)正确地设置对象的成员值,体现了聚合初始化扩展后的便利性。

8. 放宽的 constexpr 函数限制

  • 概念与作用:C++11 中引入了 constexpr 函数,但对其有诸多限制,比如函数体不能包含复杂的语句(如循环、多个返回语句等)。C++14 放宽了这些限制,允许 constexpr 函数中出现更多的语句类型,例如可以有局部变量、简单的循环等,这使得 constexpr 函数能够处理更复杂的计算逻辑,同时又能在编译期求值,进一步拓展了编译期计算的能力,有助于优化代码性能和提升代码的通用性。
  • 示例代码
#include <iostream>

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

int main() {
    constexpr int fact_5 = factorial(5);  // 在编译期计算5的阶乘
    std::cout << "5的阶乘: " << fact_5 << std::endl;
    return 0;
}

factorial 函数中,通过使用 constexpr 标记并在函数体中包含了循环语句来计算阶乘,C++14 允许这样的操作,并且可以在编译期完成计算,将结果作为常量表达式使用,展示了放宽 constexpr 函数限制后的强大功能。

这些只是C++14众多新特性中的一部分,它们从不同方面提升了C++语言的表达能力、编程便利性以及性能优化等,使得开发者可以更高效地编写高质量的C++代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值