std::ratio<1,1000> 是什么意思?


author: hjjdebug
date: 2025年 05月 14日 星期三 09:45:24 CST
description: std::ratio<1,1000> 是什么意思?


文章目录

    • 1. 它是一种数值吗?
    • 2. 它是一种类型吗?
    • 3. std:ratio 是什么呢?
    • 4. 分析一个展开后的模板函数
    • 5.小结:

前言: std::ratio 是c++11中引入的模板类.表示比例.
靠,连个比值都定义一个类,我相信c++已经做了很多类了.
想干什么事,一般找到调用方法就可以了.
这个类先假定它很复杂, 等读完会发现它很简单!

先给一个简单的例子来研究.

$ cat main.cpp
#include <iostream>
#include <ratio>
using namespace std;
// 定义一个模板函数,接受一个 std::ratio 类型参数
// 这个类型有静态变量num 和den, 由于是静态变量,会直接在代码中用常数展开.
// 这个模板函数将来会生成很多个函数,不同的类型就会生成不同的函数代码,是静态编译多态性的一种
template <typename Ratio>
void print_ratio() {printf("num:%ld,den:%ld\n",Ratio::num,Ratio::den);
}int main() {using r=std::ratio<1,1000>; //using 就是typedef, 编译时直接替换// std::ratio<1,1000> 是个类型, 而非数值,//这里类型名会与函数名共同构成一个代码中的导出函数名叫print_ratio<std::ratio<1l,1000l>>print_ratio<r>(); // 输出 Numerator: 1, Denominator: 1000// 这里std::ratio<1,10>时另一种类型,是分子为1,分母为10的类型print_ratio<std::ratio<1,10>>();//用类型实例化对象std::ratio<1,1000> obj;cout<<"num:"<<obj.num<<",den:"<<obj.den<<endl;cout<<"size_type:"<<sizeof(std::ratio<1,1000>)<<",size_obj:"<<sizeof(obj)<<endl;return 0;
}

执行:
./temp3
num:1,den:1000
num:1,den:10
num:1,den:1000
size_type:1,size_obj:1

代码中, std::ratio<1,1000> 是什么意思呢?

1. 它是一种数值吗?

它不是数值
看一下gdb 中的打印
p std::ratio<1,1000>
Attempt to use a type name as an expression

2. 它是一种类型吗?

它是一种类型.
看一下 gdb 的打印
ptype std::ratio<1,1000>
type = struct std::ratio<1, 1000> {
static const intmax_t num;
static const intmax_t den;
}
这个类型包含两个静态成员变量
p std::ratio<1,1000>::num
$1 = 1
p std::ratio<1,1000>::den
$2 = 1000

可见类型也可以包含属于自己的数值. 这2个数值在函数中用Ratio::num, Ratio::den引用过.

3. std:ratio 是什么呢?

显然它是一个模板类,因为有<>,有两个模板参数,因为给了1,1000
这样就可以由这个模板类,根据模板参数的不同,创建很多个类.
这里所说的类,就是类型.注意,只是类型,不是对象. 你可以用类型实例化一个对象,就像代码中那样.
下面看模板类的定义:

  template<intmax_t _Num, intmax_t _Den = 1>struct ratio{static constexpr intmax_t num =_Num * __static_sign<_Den>::value / __static_gcd<_Num, _Den>::value;static constexpr intmax_t den =__static_abs<_Den>::value / __static_gcd<_Num, _Den>::value;typedef ratio<num, den> type;};

这个结构看起来还是有点复杂,
static 修饰的变量叫静态变量,它是属于类的而不属于对象.
constexpr 表示它会在编译期计算出数值
intmax_t 是 long int 的别名
__static_sign<_Den>::value, 这也是一个模板类,拿到这个类的带符号的分母的value值.
__static_gcd<_Num, _Den>::value, 拿到gcd模板类的value值,该值是_Num,_Den 的最大公约数.
__static_abs<_Den>::value, 分母绝对值模板类的value值

我们假定分子,分母互质, 即gcd(num,den)=1, 分子,分母都为正数,则上式可以简化为:

template<intmax_t _Num, intmax_t _Den = 1>
struct ratio
{
static constexpr intmax_t num = _Num;
static constexpr intmax_t den = _Den;
};
这样就看清了,ratio 是一个带2参数的模板类, constexpr 的含义是编译时就付给值.

4. 分析一个展开后的模板函数

模板函数 template
void print_ratio();
当类型std::ratio<1,1000> 与函数名 print_ratio相遇时
共同构成一个完整的导出函数名叫print_ratio<std::ratio<1l,1000l>>
该名称才是真实的函数导出名称(已经被c++filt 过滤过).
真实名称是这样的:_Z11print_ratioISt5ratioILl1ELl1000EEEvv,不是给人看的,给编译器看的.
下面是函数 print_ratio<std::ratio<1l,1000l>> 的反汇编代码.
是的,函数名称是可以带角标及逗号等字符的,比c常用的字符下化线丰富了不少.
重点注释了函数中怎样使用类型std::ratio<1,1000>中的静态成员变量num及den, 就是直接用数值.

/*(gdb) disassemble/m print_ratio<std::ratio<1l, 1000l> >
Dump of assembler code for function print_ratio<std::ratio<1l, 1000l> >():
9	void print_ratio() {0x0000555555555203 <+0>:	endbr64 0x0000555555555207 <+4>:	push   %rbp0x0000555555555208 <+5>:	mov    %rsp,%rbp10		printf("num:%ld,den:%ld\n",Ratio::num,Ratio::den);0x000055555555520b <+8>:	mov    $0x3e8,%edx   //类中的静态成员,直接给1000数值为第3参数0x0000555555555210 <+13>:	mov    $0x1,%esi     //类中静态成员,直接给1数值为第2参数0x0000555555555215 <+18>:	lea    0xde8(%rip),%rdi        # 0x5555555560040x000055555555521c <+25>:	mov    $0x0,%eax0x0000555555555221 <+30>:	callq  0x555555555070 <printf@plt>11	}0x0000555555555226 <+35>:	nop0x0000555555555227 <+36>:	pop    %rbp0x0000555555555228 <+37>:	retq   End of assembler dump.*/

5.小结:

  1. 模板参数可以是整形数,例如上边的1,1000
  2. 类型名称可以带角标. 例:std::ratio<1,1000>
  3. 类型可以包含属于自己的数值. 例Ratio::num, Ratio::den
  4. 类型可以与函数名一起构成实例化后的模板函数名称. print_ratio<std::ratio<1l,1000l>>
  5. 类型实例化后的对象可以不包含任何数值. sizeof(obj)=1
  6. 类型的运行期大小也可以为0. sizeof(std::ratio<1,1000>=1,
    说明它包含的类成员变量都是编译器的常数. 例Ratio::num=1,Ratio::den=1000
  7. 一个模板类std::ratio<intmax_t num,intmax_t den>,能实例化出很多实例化类,
    std::ratio<1,1000>只是其中之一. 可以随心所欲创造很多种类型,例std::ratio<1,10)等.
  8. 类型是跟gcc 的一种约定,你定义了这种类型,gcc就认识了这种类型,你就可以使用这种类型.

言之不尽,c++相较与c而言, 有更多的内涵需要让gcc明白, gcc会理解我们更复杂的表达方式.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/906063.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

测试--测试分类 (白盒 黑盒 单元 集成)

一、按照测试目标分类&#xff08;测试目的是什么&#xff09; 主类别细分说明1. 界面测试UI内容完整性、一致性、准确性、友好性&#xff0c;布局排版合理性&#xff0c;控件可用性等2. 功能测试检查软件功能是否符合需求说明书&#xff0c;常用黑盒方法&#xff1a;边界值、…

整理了 2009 - 2025 年的【199 管综真题 + 解析】PDF,全套共 34 份文件

每年真题原卷 ✅ 每年详细解析 ✅ &#x1f4c2;【管综真题 2009-2025】 &#x1f4c2;【管综解析 2009-2025】 目录树&#xff1a; ├── 2009-2025管综真题 PDF │ ├── 2009年199管综真题.pdf │ ├── 2010年199管综真题.pdf │ ├── 2011年199管综真题.pd…

用golang实现二叉搜索树(BST)

目录 一、概念、性质二、二叉搜索树的实现1. 结构2. 查找3. 插入4. 删除5. 中序遍历 中序前驱/后继结点 一、概念、性质 二叉搜索树&#xff08;Binary Search Tree&#xff09;&#xff0c;简写BST&#xff0c;又称为二叉查找树 它满足&#xff1a; 空树是一颗二叉搜索树对…

自动化:批量文件重命名

自动化&#xff1a;批量文件重命名 1、前言 2、效果图 3、源码 一、前言 今天来分享一款好玩的自动化脚&#xff1a;批量文件重命名 有时候呢&#xff0c;你的文件被下载下来文件名都是乱七八糟毫无规律&#xff0c;但是当时你下载的时候没办法重名或者你又不想另存为重新重…

VueUse/Core:提升Vue开发效率的实用工具库

文章目录 引言什么是VueUse/Core&#xff1f;为什么选择VueUse/Core&#xff1f;核心功能详解1. 状态管理2. 元素操作3. 实用工具函数4. 浏览器API封装5. 传感器相关 实战示例&#xff1a;构建一个拖拽上传组件性能优化技巧与原生实现对比常见问题解答总结 引言 在现代前端开发…

stm32 ADC单通道转换

stm32c8t6仅有12位分辨率 1、单次转换 非扫描 1、初始化 void Ad_Init() {RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);//配置ADCCLK时钟分频,ADC的输入时钟不得超过14MHzRCC_ADCCLKConfig(RCC_PCLK2_Div6);G…

2KW压缩机驱动参考设计【SCH篇】

实物展示&#xff1a; ACDC: VAC和VAC-为交流电压检测&#xff1a; 1.C33 C34作为Y电容走线宽度要求&#xff1a; Y电容一般用于L/N到地之间&#xff08;L-PE 或 N-PE&#xff09;&#xff0c;主要作用是抑制共模干扰。其走线的电流非常小&#xff0c;推荐使用 ≥ 1mm 宽的走…

python05——循环结构

1、while循环 n0 #初始条件 while n<5: #判断print(hello python) #要重复执行的代码print(n) #注意同级代码缩进相同n1 #计数器结果&#xff1a; hello python 0 hello python 1 hello python 2 hello python 3 hello python 4 hello python 5 #求阶乘和 sum0 n1 whil…

LINUX编译、运行、测试lowcoder_CN

参考 二者没有太大差异。 LINUX编译、运行、测试lowcoder-CSDN博客 下载 git clone https://github.com/mousheng/lowcoder_CN 或 git clone https://gitcode.com/gh_mirrors/lo/lowcoder_CNcd lowcoder_CN三个模块 node-service api-service client 每个模块都有自己的…

Python 基础之函数命名

几个问题 使用描述性蛇形命名法&#xff08;snake_case&#xff09;Python函数名应使用什么大小写格式&#xff1f;为什么函数名要具有描述性&#xff1f;方法的命名规范是什么&#xff1f;函数、变量和类的命名有何区别&#xff1f; Python函数的命名有一些不可违背的硬性规…

redis 命令大全整理

http://doc.redisfans.com/ 原网址 Redis 命令分类 Key(键) Key(键)命令 exists/del/keys/type/scanobject/move/dump/migratettl/pttl/persist/expireat/pexpireat/expire/pexpirerename/renamenxsort/randomkey/restoreexists 语法:exists key [key ...] 检查一个或多…

React中useDeferredValue与useTransition终极对比。

文章目录 前言一、核心差异对比二、代码示例对比1. useDeferredValue&#xff1a;延迟搜索结果更新2. useTransition&#xff1a;延迟路由切换 三、应用场景总结四、注意事项五、原理剖析1. 核心机制对比2. 关键差异3. 代码实现原理 总结 前言 在React的并发模式下&#xff0c…

高并发内存池|定长内存池的设计

二、定长内存池的设计 设计一个定长的内存池&#xff0c;这个内存池的定长在于&#xff0c;当剩余空间使用完毕后&#xff0c;总是开辟相同长度的新空间来使用。我们会使用到一个指针来切割划分大空间为小空间。大空间是内存池向系统申请的内存大小&#xff0c;而小空间是程序…

微信小程序 自定义图片分享-绘制数据图片以及信息文字

一 、需求 从数据库中读取头像&#xff0c;姓名电话等信息&#xff0c;当分享给女朋友时&#xff0c;每个信息不一样 二、实现方案 1、先将数据库中需要的头像姓名信息读取出来加载到data 数据项中 data:{firstName:, // 姓名img:, // 头像shareImage:,// 存储临时图片 } 2…

从零开始理解Jetty:轻量级Java服务器的入门指南

目录 一、Jetty是什么&#xff1f;先看一个生活比喻 二、5分钟快速入门&#xff1a;搭建你的第一个Jetty服务 步骤1&#xff1a;Maven依赖配置 步骤2&#xff1a;编写简易Servlet&#xff08;厨房厨师&#xff09; 步骤3&#xff1a;组装服务器&#xff08;餐厅开业准备&am…

深入浅出IIC协议 - 从总线原理到FPGA实战开发 -- 第一篇:I2C总线协议深度解剖

第一篇&#xff1a;I2C总线协议深度解剖 副标题 : 两根线如何征服千亿设备&#xff1f;详解硬件工程师必须掌握的通信奥义 1. 为什么I2C仍是嵌入式经典&#xff1f; 1.1 总线拓扑的哲学 拓扑对比图 SPI需4线N片选 vs I2C仅2线级联 UART点对点 vs I2C多主从架构 成本控制实…

MySQL 索引优化以及慢查询优化

在数据库性能优化中&#xff0c;索引优化和慢查询优化是两个关键环节。合理使用索引可以显著提高查询效率&#xff0c;而识别和优化慢查询则能提升整体数据库性能。本文将详细介绍MySQL索引优化和慢查询优化的方法和最佳实践。 一、MySQL 索引优化 1.1 索引的基本概念 索引是…

vue使用Pinia实现不同页面共享token

文章目录 一、概述二、使用步骤安装pinia在vue应用实例中使用pinia在src/stores/token.js中定义store在组件中使用store登录成功后&#xff0c;将token保存pinia中向后端API发起请求时&#xff0c;携带从pinia中获取的token 三、参考资料 一、概述 Pinia是Vue的专属状态管理库…

通俗版解释CPU、核心、进程、线程、协程的定义及关系

通俗版解释&#xff08;比喻法&#xff09; 1. CPU 和核心 CPU 一个工厂&#xff08;负责干活的总部&#xff09;。核心 工厂里的车间&#xff08;比如工厂有4个车间&#xff0c;就能同时处理4个任务&#xff09;。 2. 进程 进程 一家独立运营的公司&#xff08;比如一家…

用 VS Code / PyCharm 编写你的第一个 Python 程序

用ChatGPT做软件测试 编写你的第一个 Python 程序——不只是“Hello, World”&#xff0c;而是构建认知、习惯与未来的起点 “第一行代码&#xff0c;是一个开发者认知世界的方式。” 编程的入门&#xff0c;不只是运行一个字符串输出&#xff0c;更是开始用计算机思维来理解、…