CppGuide社区 CppGuide社区
首页
  • 最新谷歌C++风格指南(含C++17/20)
  • C++17详解
  • C++20完全指南
  • C++23快速入门
  • C++语言面试问题集锦
  • 🔥C/C++后端开发常见面试题解析 (opens new window)
  • 网络编程面试题 (opens new window)
  • 网络编程面试题 答案详解 (opens new window)
  • 聊聊WebServer作面试项目那些事儿 (opens new window)
  • 字节跳动面试官现身说 (opens new window)
  • 技术简历指南 (opens new window)
  • 🔥交易系统开发岗位求职与面试指南 (opens new window)
  • 第1章 高频C++11重难点知识解析
  • 第2章 Linux GDB高级调试指南
  • 第3章 C++多线程编程从入门到进阶
  • 第4章 C++网络编程重难点解析
  • 第5章 网络通信故障排查常用命令
  • 第6章 高性能网络通信协议设计精要
  • 第7章 高性能服务结构设计
  • 第8章 Redis网络通信模块源码分析
  • 第9章 后端服务重要模块设计探索
  • 🚀 全部章节.pdf 下载 (opens new window)
  • 源码分析系列

    • leveldb源码分析
    • libevent源码分析
    • Memcached源码分析
    • TeamTalk源码分析
    • 优质源码分享 (opens new window)
    • 🔥远程控制软件gh0st源码分析
  • 从零手写C++项目系列

    • C++游戏编程入门(零基础学C++)
    • 🔥使用C++17从零开发一个调试器 (opens new window)
    • 🔥使用C++20从零构建一个完整的低延迟交易系统 (opens new window)
    • 🔥使用C++从零写一个C语言编译器 (opens new window)
    • 从零用C语言写一个Redis
  • Windows 10系统编程
  • 🔥Linux 5.x内核开发与调试 完全指南 (opens new window)
  • TCP源码实现超详细注释版.pdf (opens new window)
  • Go语言特性

    • Go开发实用指南
    • Go系统接口编程
    • 高效Go并发编程
    • Go性能调优
    • Go项目架构设计
  • Go项目实战

    • 使用Go从零开发一个数据库
    • 🔥使用Go从零开发一个编译器 (opens new window)
    • 🔥使用Go从零开发一个解释器 (opens new window)
    • 🔥用Go从零写一个编排器(类Kubernetes) (opens new window)
  • Rust编程

    • Rust编程指南
  • 数据库

    • SQL零基础指南
    • MySQL开发与调试指南
GitHub (opens new window)
首页
  • 最新谷歌C++风格指南(含C++17/20)
  • C++17详解
  • C++20完全指南
  • C++23快速入门
  • C++语言面试问题集锦
  • 🔥C/C++后端开发常见面试题解析 (opens new window)
  • 网络编程面试题 (opens new window)
  • 网络编程面试题 答案详解 (opens new window)
  • 聊聊WebServer作面试项目那些事儿 (opens new window)
  • 字节跳动面试官现身说 (opens new window)
  • 技术简历指南 (opens new window)
  • 🔥交易系统开发岗位求职与面试指南 (opens new window)
  • 第1章 高频C++11重难点知识解析
  • 第2章 Linux GDB高级调试指南
  • 第3章 C++多线程编程从入门到进阶
  • 第4章 C++网络编程重难点解析
  • 第5章 网络通信故障排查常用命令
  • 第6章 高性能网络通信协议设计精要
  • 第7章 高性能服务结构设计
  • 第8章 Redis网络通信模块源码分析
  • 第9章 后端服务重要模块设计探索
  • 🚀 全部章节.pdf 下载 (opens new window)
  • 源码分析系列

    • leveldb源码分析
    • libevent源码分析
    • Memcached源码分析
    • TeamTalk源码分析
    • 优质源码分享 (opens new window)
    • 🔥远程控制软件gh0st源码分析
  • 从零手写C++项目系列

    • C++游戏编程入门(零基础学C++)
    • 🔥使用C++17从零开发一个调试器 (opens new window)
    • 🔥使用C++20从零构建一个完整的低延迟交易系统 (opens new window)
    • 🔥使用C++从零写一个C语言编译器 (opens new window)
    • 从零用C语言写一个Redis
  • Windows 10系统编程
  • 🔥Linux 5.x内核开发与调试 完全指南 (opens new window)
  • TCP源码实现超详细注释版.pdf (opens new window)
  • Go语言特性

    • Go开发实用指南
    • Go系统接口编程
    • 高效Go并发编程
    • Go性能调优
    • Go项目架构设计
  • Go项目实战

    • 使用Go从零开发一个数据库
    • 🔥使用Go从零开发一个编译器 (opens new window)
    • 🔥使用Go从零开发一个解释器 (opens new window)
    • 🔥用Go从零写一个编排器(类Kubernetes) (opens new window)
  • Rust编程

    • Rust编程指南
  • 数据库

    • SQL零基础指南
    • MySQL开发与调试指南
GitHub (opens new window)
  • C++语言面试问题集锦 目录与说明
  • 第一章 auto与类型推导
  • 第二章 关键字static及其不同用法
  • 第三章 多态、继承和虚函数
  • 第四章 Lambda函数
  • 第五章 C++中如何使用 const 限定符
  • 第六章 Modern C++的一些最佳实践
  • 第七章 智能指针
  • 第八章 引用、万能引用等
  • 第九章 C++20相关问题
    • 问题64:C++中的概念(Concepts)是什么?
    • 问题65:C++中有哪些可用的标准属性(attributes)?
    • 问题66:什么是三路比较(3-way comparison)?
    • 问题67:解释 consteval 和 constinit 为C++带来了什么?
    • 问题68:什么是模块(modules)?它们有什么优点?
  • 第十章 特殊函数及数量规则
  • 第十一章 C++面向对象设计
  • 第十二章 程序质量
  • 第十三章 标准模板库
  • 第十四章 杂项
  • cppinterviewmostaskedquestions
zhangxf
2025-03-27
目录

第九章 C++20相关问题

# 第九章 C++20相关问题

接下来的几个问题是关于C++20中最新C++特性的一些基础知识。知道这些问题的答案,至少证明你在努力跟上这些变化。

# 问题64:C++中的概念(Concepts)是什么?

概念是对模板的一种扩展。它们是编译时断言,可以用来表达泛型算法对其模板参数的期望。

概念让你能够正式记录对模板的约束,并让编译器来强制执行这些约束。另外,你还可以利用这种强制检查,通过基于概念的重载来提高程序的编译速度。

概念的主要用途有:

  • 为模板编程引入类型检查。
  • 简化模板实例化失败时的编译器诊断信息。
  • 根据类型属性选择函数模板重载和类模板特化。
  • 约束自动类型推导。

下面是定义概念的方式:

template<typename  T>
concept  integral  = std::is_integral<T>::value;
1
2

然后可以这样使用:

auto  add(integral auto  a, integral auto  b) {
    return  a+b;
}
1
2
3

概念有哪些优点呢?

  • 模板的要求成为接口的一部分。
  • 函数的重载或类模板的特化可以基于概念。
  • 我们能得到更好的错误信息,因为编译器会将模板参数的要求与实际的模板参数进行比较。
  • 你可以使用预定义的概念,也可以定义自己的概念。
  • auto和概念的使用是统一的。你可以使用conceptName auto语法,而不是单纯使用auto。
  • 如果函数声明使用了概念,它会自动成为一个函数模板。因此,编写函数模板就像编写普通函数一样简单。

# 问题65:C++中有哪些可用的标准属性(attributes)?

首先,什么是属性?它看起来是什么样的?

一个简单的属性看起来是这样的:[[attribute]]。但它可以有参数(如[[deprecated("because")]]),也可以有命名空间(如[[gnu::unused]]),或者两者都有。

属性为实现定义的语言扩展(如GNU和IBM的语言扩展)提供了统一的标准语法。它们几乎可以在C++程序的任何地方使用,但我们今天关注的不是这些。

我们感兴趣的是C++标准定义的属性。C++11引入了第一批标准属性:

  • [[noreturn]]表示函数不会返回。这并不意味着它返回void,而是根本不会返回。这可能意味着它总是抛出异常,根据输入不同,抛出的异常也可能不同。
  • [[carries_dependency]]表示在release-consume的std::memory_order内存序下,函数内外的依赖链会传播,这使得编译器可以跳过不必要的内存屏障指令。

然后,C++14添加了另一种类型的属性,有两个版本:

  • [[deprecated]]和[[deprecated(reason)]]表示不鼓励使用该实体,可以通过参数指定原因。

C++17加快了脚步,又添加了三个属性:

  • [[fallthrough]]在switch-case语句中表示故意省略了break或return。从一个case标签直接跳到下一个是有意为之。
  • [[nodiscard]]表示函数的返回值不应该被丢弃,换句话说,必须将其保存到一个变量中,否则会得到编译器警告。
  • [[maybe_unused]]抑制对未使用实体的编译器警告。例如,如果一个变量声明时使用了[[maybe_unused]],即使它未被使用,也不会得到编译器警告。

C++20又添加了4个属性:

  • [[nodiscard("reason")]]与[[nodiscard]]相同,但指定了原因。
  • [[likely]]向编译器表明,switch-case或if-else分支中某个分支比其他分支更有可能被执行,这样编译器可以针对该求值路径进行优化。
  • [[unlikely]]与[[likely]]概念相同,但在这种情况下,标记的路径比其他路径更不可能被执行。
  • [[no_unique_address]]表示这个数据成员不必具有与它所在类的其他非静态数据成员不同的地址。

# 问题66:什么是三路比较(3-way comparison)?

三路比较运算符也被称为太空船运算符,看起来是这样的:lhs <=> rhs。

它有助于判断哪个操作数更大、更小,或者它们是否相等。

如果你在C++中实现过比较运算符,就会知道这是一项多么单调乏味的任务。你必须定义六个运算符(==、!=、<、<=、>、>=)。

有了C++20,你只需为太空船运算符使用=default,它就会为你生成所有六个constexpr且noexcept的运算符,并且这些运算符会执行字典序比较。

关于支持类型的具体规则,请查看CppReference。

# 问题67:解释 consteval 和 constinit 为C++带来了什么?

C++11引入了constexpr表达式,它可能在编译时求值。

C++20引入了两个与之相关的新关键字:consteval和constinit。

consteval可以用于函数:

consteval  int  sqr(int  n) {
    return  n * n;
}
1
2
3

consteval函数保证在编译时执行,因此它们会创建编译时常量。它们不能分配或释放数据,也不能与静态或线程局部变量交互。

constinit可以应用于具有静态存储期或线程存储期的变量。所以局部变量或成员变量不能使用constinit。它保证变量的初始化在编译时进行。

需要注意的是,constexpr和const变量一旦赋值就不能更改,而constinit变量不是常量,它的值可以改变。

# 问题68:什么是模块(modules)?它们有什么优点?

正如我们已经讨论过的,#include语句基本上是文本包含。预处理器宏会用要包含文件的内容替换#include语句。

因此,一个简单的“Hello World”程序可能会从大约100字节增长到13000字节,仅仅是因为包含了<iostream>。

即使你只想使用其中一个小函数,所有的头文件内容都会被复制。

C++20引入的模块最终提供了解决方案。导入一个模块基本上没有开销,与包含头文件不同,导入的顺序也无关紧要。

有了模块,你可以轻松构建自己的库,通过export限定符,你可以轻松决定哪些内容要暴露,哪些不要。

多亏了模块,不再需要将头文件和实现文件分开。

下面是一个简短的示例:

// math.cppm
export  module  math;

export  int  square(int  n){
    return  n*n;
}

// main.cpp
import  math;

int  main(){
    square(42);
}
1
2
3
4
5
6
7
8
9
10
11
12
13

想要了解更多细节(有很多!),可以参考《C++20完全指南 (opens new window)》。

上次更新: 2025/03/27, 20:29:48
第八章 引用、万能引用等
第十章 特殊函数及数量规则

← 第八章 引用、万能引用等 第十章 特殊函数及数量规则→

最近更新
01
第二章 关键字static及其不同用法
03-27
02
第一章 auto与类型推导
03-27
03
第四章 Lambda函数
03-27
更多文章>
Copyright © 2024-2025 沪ICP备2023015129号 张小方 版权所有
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式