author: hjjdebug
date: 2025年 05月 14日 星期三 09:45:24 CST
description: std::ratio<1,1000> 是什么意思?
先给一个简单的例子来研究.
$ cat main.cpp
#include
#include
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>
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> 是什么意思呢?
它不是数值
看一下gdb 中的打印
p std::ratio<1,1000>
Attempt to use a type name as an expression
它是一种类型.
看一下 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引用过.
显然它是一个模板类,因为有<>,有两个模板参数,因为给了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
struct ratio
{
static constexpr intmax_t num = _Num;
static constexpr intmax_t den = _Den;
};
这样就看清了,ratio 是一个带2参数的模板类, constexpr 的含义是编译时就付给值.
模板函数 template
void print_ratio();
当类型std::ratio<1,1000> 与函数名 print_ratio相遇时
共同构成一个完整的导出函数名叫print_ratio
该名称才是真实的函数导出名称(已经被c++filt 过滤过).
真实名称是这样的:_Z11print_ratioISt5ratioILl1ELl1000EEEvv,不是给人看的,给编译器看的.
下面是函数 print_ratio
是的,函数名称是可以带角标及逗号等字符的,比c常用的字符下化线丰富了不少.
重点注释了函数中怎样使用类型std::ratio<1,1000>中的静态成员变量num及den, 就是直接用数值.
/*
(gdb) disassemble/m print_ratio >
Dump of assembler code for function print_ratio >():
9 void print_ratio() {
0x0000555555555203 <+0>: endbr64
0x0000555555555207 <+4>: push %rbp
0x0000555555555208 <+5>: mov %rsp,%rbp
10 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 # 0x555555556004
0x000055555555521c <+25>: mov $0x0,%eax
0x0000555555555221 <+30>: callq 0x555555555070
11 }
0x0000555555555226 <+35>: nop
0x0000555555555227 <+36>: pop %rbp
0x0000555555555228 <+37>: retq
End of assembler dump.
*/
言之不尽,c++相较与c而言, 有更多的内涵需要让gcc明白, gcc会理解我们更复杂的表达方式.