前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >全面盘点17个C++17的高级特性

全面盘点17个C++17的高级特性

作者头像
公众号guangcity
发布2024-03-22 12:56:47
2.5K0
发布2024-03-22 12:56:47
举报
文章被收录于专栏:光城(guangcity)

全面盘点17个C++17的高级特性

C++17是目前比较常用的版本之一,今天花时间来梳理一下17个重要特性,所有的特性也不止这么点。

1. 并行算法

C++17引入了许多并行版本的标准库中的算法。这些算法可以并行执行,因此在多核系统上可能会带来显著的性能提升。

之前写过一篇全面介绍这个特性的文章,可以看这篇:未来已来:C++17 并行STL性能测评

例子:

代码语言:javascript
复制
#include <algorithm>
#include <vector>
#include <execution>
int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    std::sort(std::execution::par, v.begin(), v.end());
}

在此例子中,std::sort是并行执行的,以并行方式对向量v的元素进行排序。

2. If Initializers

C++17中的If初始化器是一项特性,它允许在if语句中直接初始化变量。这种初始化方式在一定程度上可以提高代码的可读性和简洁性。

在传统的C++中,我们通常会这样初始化变量:

代码语言:javascript
复制
int x;
if (condition) {
    x = 42;
} else {
    x = 24;
}

而在C++17中,可以使用if初始化器来简化这个过程,使代码更加紧凑:

代码语言:javascript
复制
if (bool condition = /* some condition */) {
    int x = 42;
} else {
    int x = 24;
}

在这个例子中,我们将变量x的初始化直接放在if语句中。变量condition在if语句中被定义和初始化,然后在if语句块中可用。这种方式更加直观和简洁,尤其是在简单的条件初始化时。

3. 类模板参数推导(CTAD)

CTAD 让编译器从类参数中自动推导出模板参数。这使得在不必显式指定模板参数的情况下更容易地使用模板。

往期对这个特性的全面阐述文章:C++17那些事开篇之类模版参数推导(CTAD)

例如下面函数模版的例子(C++17之前):

代码语言:javascript
复制
template <typename T>
void foo(T t) {
    // ...
}

int main() {
    foo(42);  // 编译器推导出T的类型为int
}

在此例子中,当调用foo(42)时,编译器推导出T的类型是int.

4. template <auto>

模板关键词被引入为非类型模板参数的占位符。它允许在模板中表示任何类型的值。

例子:

代码语言:javascript
复制
template<auto value>
struct constant {
    static constexpr auto get_value() { return value; }
};

// 用法
static_assert(constant<42>::get_value() == 42);

5. std::optional 和 std::variant

std::optionalstd::variant 是C++17中引入的两个新类型。std::optional 表示一个可能存在也可能不存在的值,std::variant 代表一个类型安全的联合,可以保存不同类型的值。

例子:

代码语言:javascript
复制
#include <optional>
#include <variant>

int main() {
    std::optional<int> opt = 42;
    std::variant<int, double> var = 3.14;
}

在这个例子中,opt是包含值42的可选整数,var是包含值3.14的变体。

6. 折叠表达式

在C++17中,折叠表达式提供了一种简洁的方式,用于对参数包执行二元操作。它们允许在不需要显式递归或迭代的情况下执行诸如求和、乘法或连接参数包中元素的操作。

例如:

代码语言:javascript
复制
#include <iostream>

template<typename T>
T sum(T t) {
    return t;
}

// 使用折叠表达式的递归情况
template<typename T, typename... Args>
T sum(T first, Args... args) {
    return first + sum(args...);
}

int main() {
    int total = sum(1, 2, 3, 4, 5);
    std::cout << "总和: " << total << std::endl;
    
    return 0;
}

递归sum函数中的折叠表达式(first + ... + args)对参数包中的每个元素应用了加法操作。

7. 结构化绑定

结构化绑定允许你将对象分解成其构成元素,类似于你可能会用到的元组拆包。

往期文章:C++17结构化绑定

例子:

代码语言:javascript
复制
#include <tuple>
#include <string>
int main() {
    std::tuple<int, std::string, double> t(42, "hello", 3.14);
    auto [i, s, d] = t;  // i = 42, s = "hello", d = 3.14
}

在此例子中,结构化绑定[i, s, d]将元组t分解成其构成元素。

8.模板模板参数

例如:在C++17中,语法 template<template<class...>typename bob> struct foo {} 声明了一个名为 foo 的模板,它接受一个名为 bob 的模板模板参数。模板模板参数 bob 本身接受任意数量的模板类型参数。

代码语言:javascript
复制
template <template<class...> typename bob>
struct foo {
    template<typename T>
    void bar(const bob<T>& arg) {
        std::cout << "size: " << arg.size() << std::endl;
    }
};

int main() {
    foo<std::vector> f;
    std::vector<int> vec = {1, 2, 3, 4, 5};
    f.bar(vec);

    return 0;
}

main 函数中,我们使用 std::vector 实例化了 foo,将其作为 bob 的模板参数。这使我们能够创建一个通用的结构 foo,可以与任何接受任意数量类型参数的模板一起工作,例如 std::vectorstd::list 或用户定义的模板。

9. 内联变量

C++17允许在类的定义内部定义变量为内联的,这可以帮助减小二进制大小,可能通过防止变量在多个转换单元中的重复副本来提高性能。

例子:

代码语言:javascript
复制
class MyClass {
public:
    inline static int inlineVar = 42;
};

int main() {
    int localVar = MyClass::inlineVar;
}

在这里,inlineVarMyClass的内联静态成员变量。

10. 属性改进

C++17提供新的属性,并改进了已有的属性,允许开发人员为编译器提供更多的代码行为信息。

例子:

代码语言:javascript
复制
[[nodiscard]] int get_sum(int a, int b) {
    return a + b;
}

int main() {
    auto result = get_sum(1, 2);
    // 编译器可能会警告‘result’未使用
}

在此例子中,[[nodiscard]]是可以应用于函数的属性,表示其返回值不应该被调用者丢弃。

11. 嵌套命名空间

C++17通过折叠表达式增强了变参模板,使得在处理参数包时的代码更为简洁和表达明了。

例子:

代码语言:javascript
复制
// 外部命名空间
namespace outer {
    // 内部命名空间
    namespace inner {
        void foo() {
            std::cout << "在内部命名空间中" << std::endl;
        }
    }
}

outer::inner::foo();

嵌套命名空间定义提供了一种将代码层次化组织的方式,提高了可读性和可维护性,尤其是在大型项目中。它们还通过提供更加结构化的命名空间层次结构来帮助避免命名冲突。

12. 字面量改进

C++17增强了字面量,包括对整数和浮点字面量的改进,以及对真和假字面量的支持。

例子:

代码语言:javascript
复制
auto num = 123_456; // Underscore in integer literals  
auto pi = 3.1415_f; // Suffix for floating-point literals

13. constexpr Lambda

C++17允许lambda函数成为constexpr,如果它们满足条件,就可以在需要编译时评估的上下文中使用,例如:

代码语言:javascript
复制
constexpr auto lambda = [](int x) { return x * 2; };
static_assert(lambda(5) == 10);

在这个例子中,lambda是一个constexpr lambda,它接受一个整数x作为参数,然后返回x的两倍。static_assert检查在编译时,lambda(5)的值是否等于10。

14. 捕获*this

在lambda中捕获*this变得更加简单,允许直接访问包含对象的成员。

代码语言:javascript
复制
class Foo {
    int data = 42;
public:
    auto member_lambda() {
        return [*this] { std::cout << data << std::endl; };
    }
};

// 使用
Foo f;
f.member_lambda()(); // 输出 "42"

15. 扩展的if和switch语句

ifswitch语句中的条件现在可以是任何表达式,不仅限于布尔条件。这使得控制流更加灵活,例如使用结构化绑定时:

代码语言:javascript
复制
if (const auto [it, inserted] = map.insert({"foo", bar}); inserted) {
    // ...
}

在此例子中,if语句检查inserted变量是否为真,但条件还包括结构化绑定的赋值。

16. 泛化的基于范围的for循环

此改进支持不同于起始迭代器类型的标志或结束迭代器,这有助于处理以空终止的循环和其他类似情况。例如:

代码语言:javascript
复制
for (auto it = my_container.begin(); it != my_container.end(); ++it) {
   // ...
}

在此例子中,my_container可能是使用不同类型的结束迭代器的容器,但循环仍然可以正确工作。

17. if constexpr

此特性通过允许编译器在编译时评估条件,从而实现更通用的代码。如果条件为真,则编译的代码中包含if块内的代码;否则,它将被丢弃。这可以通过在运行时删除不必要的分支来简化代码。例如:

代码语言:javascript
复制
if constexpr (std::is_same_v<T, int>) {
   // 用于int的特定代码
} else {
   // 用于其他类型的代码
}

在这个例子中,if constexpr语句检查类型T是否为int,并相应地包含适当的代码。

总结

本节就先写这么多,其他内容下一节进行阐述。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-03-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 光城 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 全面盘点17个C++17的高级特性
  • 1. 并行算法
  • 2. If Initializers
  • 3. 类模板参数推导(CTAD)
  • 4. template <auto>
  • 5. std::optional 和 std::variant
  • 6. 折叠表达式
  • 7. 结构化绑定
  • 8.模板模板参数
  • 9. 内联变量
  • 10. 属性改进
  • 11. 嵌套命名空间
  • 12. 字面量改进
  • 13. constexpr Lambda
  • 14. 捕获*this
  • 15. 扩展的if和switch语句
  • 16. 泛化的基于范围的for循环
  • 17. if constexpr
  • 总结
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档