[译]C++17, 语言核心层变化的更多细节

在之前的文章中,我介绍了一些c++++17语言核心层的变化。这次我将详细探讨更多相关的细节,涉及的主题包括:内联变量(inline variables)、模板、auto相关的自动类型推导以及属性(attributes)。

C++标准整体的特性时间线

[译]C++17, 语言核心层变化的更多细节上图列出了C++17的主要特性,而本文将介绍一些不太为人所知的特性。

内联变量(Inline variables)过去我们不将C++代码打包成仅含头文件的程序库(header-only libraries)的一个主要原因是为了正确处理相同的变量引用。C++17引入了内联变量,解决了这个问题!现在你可以声明内联的全局变量和静态变量了,相关的规则限制与内联函数一致。

这意味着:

立即学习“C++免费学习笔记(深入)”;

你可以重复定义一个内联变量,但该内联变量必须在使用它的编译单元中可见。一个全局内联变量(即非静态内联变量)必须在每一个编译单元中进行声明,并且该全局内联变量在每一个编译单元中都有相同的内存地址。现在你能直接在头文件中声明(内联)变量并且多次包含它们(包含对应的头文件)了!

class Widget{  public:    Widget() = default;    Widget(int w): width(w), height(getHeight(w)){}    Widget(int w, int h): width(w), height(h){}  private:    int getHeight(int w){ return w*3/4; }    static inline int width= 640;    static inline int height= 480;    static inline bool frame= false;    static inline bool visible= true;    ...;};inline Widget wVGA;

auto可以根据其初始化表达式自动推导变量类型。在C++17中,auto的这种自动类型推导能力进一步增强了。借助auto,函数模板和(类模板的)构造函数的模板参数可以根据其参数自动进行类型推导(细节介绍),非类型模板参数的类型也可以从参数中自动推导出来。下面我将介绍一下非类型模板参数的自动类型推导。

非类型模板参数(non-type template parameters)的自动类型推导首先要说明一下哪些属于非类型模板参数:它们是nullptr、整型、左值引用、指针以及枚举类型。下面的讲解主要以整型为主。

说了这么多理论,是时候看个示例了:

template class MyClass{  ...;};template class MyClass {  ...;};MyClass myClass2;     // Primary template for charMyClass myClass1;   // Partial specialisation for int

第1行代码中,通过将模板参数声明为auto,编译器便可以自动推导非类型模板参数(第1行代码中的N)的类型了,你甚至可以像示例代码中那样(第7和第8行)偏特化该模板(示例代码中为int类型进行了偏特化)。第13行代码的模板会依据原始模板(示例中的第一个模板)进行实例化,而第14行代码的实例化依据的则是偏特化模板版本(示例中的第二个模板)。

一般的类型修饰符也可以用在非类型模板参数上,所以很多时候,你不必非得使用模板偏特化来限制非类型模板参数的类型。

template struct S;

上述代码中,p被限制成必须是常量指针类型。

即便在可变参数模板中,非类型模板参数也可以进行自动类型推导。

template class VariadicTemplate{  ...;};template class TypedVariadicTemplate{  ...;};

示例代码中,模板VariadicTemplate(第1行至第5行)可以对任意数量的非类型模板参数进行自动类型推导,而TypeVariadicTemplate模板(第7行至第11行)则仅会自动推导第一个非类型模板参数的类型,其余非类型模板参数的类型都与第一个非类型模板参数的类型相同。

C++17更改了auto结合使用列表初始化的规则。

auto结合使用{}初始化在C++17之前,如果你结合使用auto和列表初始化,你会得到一个std::initializer_list。

auto initA{1};          // std::initializer_listauto initB = {2};       // std::initializer_listauto initC{1, 2};       // std::initializer_listauto initD = {1, 2};    // std::initializer_list

这个规则很容易记忆,也很容易教授,但在C++17中,这个规则变复杂了(个人感觉这个改动并不好)。

auto initA{1};          // intauto initB = {2};       // std::initializer_listauto initC{1, 2};       // error, no single elementauto initD = {1, 2};    // std::initializer_list

现在,使用初始化列表进行赋值依然会得到类型std::initializer_list,但使用初始化列表进行复制构造却只支持单个数值了,得到的类型也不再是std::initializer_list,而是对应的初始化数值类型。

接下来让我们来看一些小而美的特性。

Nested namespaces在C++17中,你可以非常简便地定义嵌套的命名空间。

相比之前的写法:

namespace A {  namespace B {    namespace C {      ...;    }  }}

C++17中的写法要简明很多:

namespace A::B::C {  ...;}

C++17新增了三个属性[[fallthrough]]、[[nodiscard]]和[[maybe_unused]]。

新增的三个属性fallthrough、nodiscard、maybe_unused这三个属性都是为了处理编译器警告,下面的例子来自于cppreference.com。

fallthrough[[fallthrough]]可以在switch语句中使用,他必须单独占据一行代码,并且后面需要跟随一个case标签(或者default标签)语句,以此来说明代码从[[fallthrough]]的前一个标签“落下”(继续执行后面标签的逻辑,而不break)是有意为之的,编译器不应该诊断其为警告。

这里有个例子:

void f(int n) {  void g(), h(), i();  switch (n) {    case 1:    case 2:      g();      [[fallthrough]];    case 3: // no warning on fallthrough      h();    case 4: // compiler may warn on fallthrough      i();      [[fallthrough]]; // ill-formed, not before a case label  }}

代码第9行的[[fallthrough]]属性抑制了编译器的编译警告,但是代码第12行由于缺少[[fallthrough]]属性,编译器便有可能产生告警。第14行代码的[[fallthrough]]声明是病态的,因为其后没有跟随case标签(或者default标签)。

nodiscard[[nodiscard]]属性可以用于函数声明、枚举声明以及类声明中。如果你丢弃了一个声明为[[nodiscard]]的函数的返回值,编译器就会产生一个编译警告。同样地,如果你丢弃了函数中返回的(声明为)[[nodiscard]]枚举或者(声明为)[[nodiscard]]类,编译器同样会给出警告,抑制该类警告的一种方法就是对返回值进行一次void转型操作。

下面的示例中,第6行代码会产生一个编译警告,但在第12行代码中,由于foo函数返回的是引用类型(虽然引用类型本身是[[nodiscard]]属性),所以不会产生编译警告。

struct [[nodiscard]] error_info {};error_info enable_missile_safety_mode();void launch_missiles();void test_missiles() {  enable_missile_safety_mode(); // compiler may warn on discarding a nodiscard value  launch_missiles();}error_info& foo();void f1() {  foo(); // nodiscard type is not returned by value, no warning}

maybe_unused可以使用[[maybe_unused]]的地方很多:类、typedef、变量、非静态成员变量、函数、枚举类型或者枚举值。[[maybe_unused]]可以抑制编译器对于代码中未使用实体的编译警告。

void f([[maybe_unused]] bool thing1,       [[maybe_unused]] bool thing2){  [[maybe_unused]] bool b = thing1;  assert(b); // in release mode, assert is compiled out}

release模式下,上面第5行代码在编译时会被移除,但是由于我们之前为b声明了[[maybe_unused]]属性,所以编译器不会产生警告,同样地,虽然代码中也没有使用参数thing2,但是由于thing2也声明了[[maybe_unused]]属性,所以也不会产生编译警告。

以上就是[译]C++17, 语言核心层变化的更多细节的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/9668.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
挑选三星手机屏幕指南—三星手机屏幕选购技巧详解
上一篇 2025年11月11日 03:39:45
CVPR 2024高分论文:全新生成式编辑框架GenN2N,统一NeRF转换任务
下一篇 2025年11月11日 03:41:31

相关推荐

  • Linux内核13-进程切换

    进程切换,也称为任务切换、上下文切换或任务调度,本文将探讨linux内核中进程切换的实现。我们首先理解几个关键概念。 1.1 硬件上下文 每个进程都有自己的地址空间,但所有进程共享CPU寄存器。因此,在恢复进程执行前,内核必须确保挂起时的寄存器值被重新加载到CPU寄存器中。 这些需要加载到CPU寄存…

    2026年9月22日
    200
  • PHP三元运算符复杂条件_PHP三元运算符多条件处理

    三元运算符可通过逻辑运算符或嵌套实现多条件判断,如链式写法 $result = ($a > 5 && $b == 90) ? ‘优秀’ : $score >= 80 ? ‘良好’ : $score >= 60 ? &#…

    2026年9月22日
    000
  • Android自定义开关UI实现教程

    本文详细介绍了在Android应用中实现自定义开关UI的两种主要方法:一是通过集成第三方库如StickySwitch,快速实现美观且功能丰富的开关;二是通过结合Drawable XML和ToggleButton,实现高度定制化的开关外观。文章提供了详细的代码示例和配置说明,旨在帮助开发者灵活地创建符…

    2026年9月22日
    000
  • MySQL安装时端口冲突如何解决?

    MySQL安装时端口冲突如何解决?MySQL安装时端口冲突如何解决?MySQL安装时端口冲突如何解决?MySQL安装时端口冲突如何解决?

    mysql安装时3306端口冲突的解决方法有两类:1.修改mysql默认端口;2.找出并停止占用端口的进程。在安装过程中可通过mysql安装向导直接修改端口号,或安装后编辑配置文件my.ini(windows)或my.cnf(linux)中的port参数,并重启mysql服务生效。若确认3306应为…

    2026年9月22日 用户投稿
    900
  • Linux进程调度学习!

    进程调度决定了哪个进程将被执行以及执行的时间,操作系统通过合理的进程调度实现资源的最大化利用。 在单片机上,常见的方式是系统初始化后进入 while(1){} 循环。当然,单片机也可以运行类似 FreeRTOS 的系统,从而实现进程切换。 在带有操作系统的 CPU 上运行的逻辑是允许多个进程(实际上…

    2026年9月22日
    000
  • 《零红蝶》重制版与原版对比截图 画面进化但有和谐

    《零红蝶》重制版与原版对比截图 画面进化但有和谐《零红蝶》重制版与原版对比截图 画面进化但有和谐《零红蝶》重制版与原版对比截图 画面进化但有和谐《零红蝶》重制版与原版对比截图 画面进化但有和谐

    之前光荣特库摩公开了恐怖游戏《零红蝶:重制版》,本作计划于2026年初发售,登陆ps5、xsx/s、steam以及switch2平台,并支持中文语言。近日,有网友晒出对比截图,将原版、wii版与即将推出的重制版进行了画面对比。 从图片可以看出,相较于原版和Wii版本,重制版在视觉表现上实现了巨大飞跃…

    2026年9月22日 用户投稿
    300
  • 好用的终端复用神器-Tmux

    好用的终端复用神器-Tmux好用的终端复用神器-Tmux好用的终端复用神器-Tmux好用的终端复用神器-Tmux

    前言 许久之前就听说过tmux,但是一直没上手,直到最近需要一直在linux下完成一些任务,我才切实感受到了tmux的优点:任意分屏、保存工作 就单单这两点,就足够实用了。分屏,曾今还十分痴迷i3wm和dwm这样的窗口管理工具,尤其是dwm的操作逻辑,大大提升linux工作效率。其他详情可以查看阮一…

    2026年9月22日 用户投稿
    200
  • VSCode安装C/C++插件 小白必备VSCode配置C语言教程

    安装C/C++插件并配置MinGW编译器,通过tasks.json和launch.json文件设置编译调试任务,可使VSCode支持C语言开发;若插件异常,需检查环境变量、文件路径及语法,必要时重启或重装;中文乱码可通过设置UTF-8编码、使用集成终端或程序内setlocale解决;远程开发需配合R…

    2026年9月22日
    000
  • 电脑win11使用vnc连接手机ubuntu

    电脑win11使用vnc连接手机ubuntu电脑win11使用vnc连接手机ubuntu电脑win11使用vnc连接手机ubuntu电脑win11使用vnc连接手机ubuntu

    由于互联需要,使用vnc,手机端开发代码太伤眼睛了。 www.realvnc.com/en/connect/download/viewer/ 选择standalone exe x64,试一试看看??? 使用版本VNC-Viewer-6.21.1109-Windows-64bit。 双击打开,同意条款…

    2026年9月22日 用户投稿
    200
  • VSCode如何配置Rust开发环境 VSCode搭建Rust项目的详细步骤

    安装rust工具链需在终端运行curl –proto ‘=https’ –tlsv1.2 https://sh.rustup.rs -ssf | sh,安装完成后重启终端或执行source $home/.cargo/env,并通过rustc &#821…

    2026年9月22日
    000
  • VSCode配置FPGA的CI/CD流程(自动化测试与部署指南)

    答案是:使用VSCode配置FPGA的CI/CD流程完全可行,通过tasks.json和launch.json集成脚本化构建、仿真、测试与烧录任务,结合Git版本控制与Docker环境封装,实现设计流程自动化;利用Cocotb等框架构建可复用、高覆盖率的自动化测试环境,并通过统一项目结构和CI/CD…

    2026年9月22日
    200
  • Swift 3到5.1新特性整理

    tocSwift 5.1Swift 5.0Result类型Raw string自定义字符串插值动态可调用类型处理未来的枚举值从try?抹平嵌套可选检查整数是否为偶数字典compactMapValues()方法撤回的功能: 带条件的计数Swift 4.2CaseIterable协议警告和错误指令动态查…

    2026年9月22日
    100
  • php-gd怎么制作缩略图_php-gd生成高质量缩略图

    使用PHP-GD生成高质量缩略图需保持宽高比、选用imagecopyresampled进行重采样,并合理设置JPEG质量(80-95),同时处理PNG透明通道,避免图像失真或背景变黑。 使用 PHP-GD 制作高质量缩略图,核心在于正确处理图像缩放、保持宽高比、避免失真,并选择合适的图像质量参数。下…

    2026年9月22日
    000
  • VSCode配合Vivado进行FPGA图像处理(算法加速与优化)

    答案:VSCode与Vivado结合可提升FPGA图像处理开发效率,前者用于代码编辑、版本控制和远程开发,后者负责综合、实现与调试,二者协同实现高效算法优化。 将VSCode与Vivado结合用于FPGA图像处理,本质上是利用VSCode作为高效的代码编辑、版本控制和辅助开发环境,来弥补Vivado…

    2026年9月22日
    200
  • VSCode搭建FPGA与ROS通信环境(机器人控制,硬件加速指南)

    VSCode可高效集成FPGA与ROS开发,通过远程SSH连接实现跨环境代码编辑、任务自动化与调试,结合FPGA通信接口设计与ROS节点开发,统一硬件与软件工作流,提升开发效率。 将VSCode作为FPGA与ROS通信的集成开发环境是完全可行的,甚至可以说,它是一个非常高效且灵活的选择。核心在于利用…

    2026年9月22日
    200
  • VSCode安装C/C++文档查看 提升开发效率的VSCode技巧

    答案是利用C/C++扩展和cppreference插件实现高效文档查阅。首先安装微软官方C/C++扩展,启用智能感知与悬停提示;再安装cppreference扩展,通过命令面板直接搜索标准库函数,实现离线在线无缝查阅;结合Doxygen生成项目文档,使用“转到定义”功能快速跳转源码;同时借助Inte…

    2026年9月22日
    100
  • NFV中:DPDK与SR-IOV应用场景及性能对比

    NFV中:DPDK与SR-IOV应用场景及性能对比NFV中:DPDK与SR-IOV应用场景及性能对比NFV中:DPDK与SR-IOV应用场景及性能对比NFV中:DPDK与SR-IOV应用场景及性能对比

    关于作者 作者简介: 张帅,Wechat:yorkszhang 网站:www.flowlet.net DPDK和SR-IOV目前主要用于提升IDC(数据中心)中的网络数据包处理速度。然而,在NFV(网络功能虚拟化)场景下,DPDK与SR-IOV各自的应用场景和优缺点是什么呢?本文将从以下几个方面来探…

    2026年9月22日 用户投稿
    000
  • VSCode搭建Vivado开发环境(详细配置指南,FPGA开发必备)

    答案:通过安装Verilog/SystemVerilog和Tcl扩展、配置Linter进行语法检查,并在tasks.json中定义调用Vivado命令行的任务,可在VSCode中实现RTL开发、语法高亮、智能提示及综合仿真等自动化流程,提升FPGA开发效率。 将VSCode作为Vivado的开发前端…

    2026年9月22日
    100
  • PHP如何锐化图片效果_PHP对图片进行锐化处理

    PHP通过GD库或Imagick扩展实现图片锐化,核心是利用卷积算法增强边缘对比度;GD库使用imageconvolution()函数配合锐化矩阵处理,适合基础需求,而Imagick支持更精细的非锐化蒙版等高级算法,效果更优但需额外安装;锐化能提升视觉质量和用户体验,间接有利于SEO,但需避免过度锐…

    2026年9月22日
    300
  • 笔记—Linux安装OpenCV及VSCode的配置编译

    笔记—Linux安装OpenCV及VSCode的配置编译笔记—Linux安装OpenCV及VSCode的配置编译笔记—Linux安装OpenCV及VSCode的配置编译笔记—Linux安装OpenCV及VSCode的配置编译

    在学习新技能的过程中,我选择了在linux系统上进行操作,这对于从未接触过linux的人来说是一个绝佳的学习机会。这篇文章记录了我在linux上安装opencv的过程。 我选择的Linux发行版是Ubuntu 20.04.3,并将其安装在Virtual Box虚拟机中。Ubuntu的相关资料丰富,选…

    2026年9月22日 用户投稿
    300

发表回复

登录后才能评论
关注微信