用C语言实现模板类的一些个人思路
用C语言实现模板类的一些个人思路
0. FAQ
- Q: 为什么要用模板?
- A: 为了解决函数重载问题。例如,在C++中,我们要比较两个int型变量的哪个大,并返回其中较大的值,可能会写这样的函数:
int Max(int a, int b) { return a > b ? a : b; }
int main() {printf("%d\n", Max(123, 456));return 0;
}
但是,如果我们还要比较更多的类型,例如char型,double型之类的,我们都需要重新写一个类似的实现,这很不方便:
char Max(char a, char b) { return a > b ? a : b; }
double Max(double a, double b) { return a > b ? a : b; }
int main() {printf("%c, %lf\n", Max('a', 'z'), Max(1.1, 2.2));return 0;
}
这个时候我们可以考虑使用模板来简化代码:
template <typename T>
T Max(T a, T b) { return a > b ? a : b; }
int main() {printf("%d, %c, %lf\n", Max(123, 456), Max('a', 'z'), Max(1.1, 2.2)); return 0;
}
- Q: C能重载?
- A: 不能,C只能像这样子:
int Max_int(int a, int b) { return a > b ? a : b; }
char Max_char(char a, char b) { return a > b ? a : b; }
double Max_double(double a, double b) { return a > b ? a : b; }
int main() {printf("%d, %c, %lf\n", Max_int(123, 456), Max_char('a', 'z'), Max_double(1.1, 2.2));return 0;
}
- Q: 道理我都懂,有C++了,为什么还要用C实现模板?
- A: 虽然一般情况下都能直接写C++来代替C程序啦,不过确实存在无法使用C++的场合。很不幸,我工作所用的语言只能是C,于是,之前用惯了C++的我决定探索一下如何用C实现模板- -+
1. 目前个人写法风格
1.0 模板函数
首先,用前面的Max函数为例,先看一下我目前的写法风格吧:-P
需要注意的是:为防止宏嵌套出错,例如_Max(Pair(int, char))
会被拓展成Max$_Pair(int, char)_$
这样的不合法变量名(Pair的定义见1.1模板类示例),我们都需要多写一个类似于#define Max(T) _Max(T)
这样的操作
#define _Max(T) Max$_##T##_$
#define Max(T) _Max(T)#define _Max_IMPL(T) T Max(T)(T a, T b) { return a > b ? a : b; }
#define Max_IMPL(T) _Max_IMPL(T)Max_IMPL(int);
Max_IMPL(char);
Max_IMPL(double);int main() {printf("%d, %c, %lf\n", Max(int)(123, 456), Max(char)('a', 'z'), Max(double)(1.1, 2.2));return 0;
}
下面解释一下上面的代码到底做了什么:
用宏来模仿C++的写法 ——
#define _Max(T) Max$_##T##_$
这里用了Max(T)
宏来模仿C++的Max<T>
写法。例如:
Max(int)
,宏拓展后实际上等于Max$_int_$
($
符号确实是合法变量名),这里用$_
表示C++中模板的尖括号左侧<
,用_$
表示尖括号右侧>
模板实现 ——
#define _Max_IMPL(T) T Max(T a, T b) { return a > b ? a : b; }
相当于C++的template <typename T> T Max(T a, T b) { return a > b ? a : b; }
实例化模板 ——
Max_IMPL(int);
由于C不是C++,所以需要使用者自己去实例化对应的模板类型,此处宏拓展出来的代码为int Max(int)(int a, int b) { return a > b ? a : b; }
,然后Max(int)
再拓展为Max$_int_$
,于是最终结果为:
int Max$_int_$(int a, int b) { return a > b ? a : b; }
使用 ——
Max(int)(123, 456)
相当于C++的Max<int>(123, 456)
像这样,我们就实现了一个T Max<T>(T, T)
模板函数了!在此基础上,我们可以更进一步:如果能做一个检测代码中Max使用了哪些模板类型,然后在编译前自动添加实现Max_IMPL(…)完成“实例化”的程序,就可以完成类似于C++的模板类型推断功能了- -+
1.1 模板类
模板类同理,我们以简单的Pair为例(保存两个类型数据的结构)
#define _Pair(T1, T2) Pair$_##T1##_$$_##T2##_$
#define Pair(T1, T2) _Pair(T1, T2)#define _Pair_IMPL(T1, T2) typedef struct { T1 t1; T2 t2; } Pair(T1, T2)
#define Pair_IMPL(T1, T2) _Pair_DEF(T1, T2)Pair_IMPL(int, char);
Pair_IMPL(int, double);int main() {Pair(int, char) p_ic;Pair(int, double) p_id;p_ic.t1 = 123;p_ic.t2 = 'a';p_id.t1 = 456;p_id.t2 = 1.1;return 0;
}
#define _Pair(T1, T2) Pair$_##T1##_$$_##T2##_$
用Pair(T1, T2)
模仿C++中Pair<T1, T2>
的写法#define _Pair_IMPL(T1, T2) typedef struct Pair(T1, T2) { T1 t1; T2 t2; } Pair(T1, T2)
相当于template<typename T1, typename T2> struct Pair{ T1 t1; T2 t2; }
Pair_IMPL(int, char);
实例化Pair<int, char>
,此处宏拓展的最终结果为:
typedef struct { int t1; char t2; } Pair$_int_$$_char_$
Pair(int, char) p_ic;
相当于Pair<int, char> p_ic;
像这样,我们就完成了简单的Pair<T1, T2>
模板类了
个人项目(完善中):https://github.com/NumbFish-Luo/NfLib
参考资料:C语言宏高级用法 https://www.cnblogs.com/alantu2018/p/8465911.html
用C语言实现模板类的一些个人思路相关推荐
- 【C++ 语言】面向对象 ( 模板编程 | 函数模板 | 类模板 )
文章目录 函数模板 类模板 代码示例 函数模板 1. 模板编程 : 类似于 Java 中的泛型编程 ; ① 函数模板 : 对应着 Java 中的泛型方法 ; ② 类模板 : 对应 Java 中的泛型类 ...
- 《C++语言基础》实践参考——复数模板类
返回:贺老师课程教学链接 [项目6-复数模板类] 阅读教材例10.1.该例实现了一个复数类,但是美中不足的是,复数类的实部和虚部都固定只能是double型的.可以通过模板类的技术手段,设计Co ...
- Xamarin XAML语言教程模板页面TemplatedPage
Xamarin XAML语言教程模板页面TemplatedPage 模板页面TemplatedPage 在上文中我们提到了TemplatedPage,它被称为模板页面,用来显示控件模版.Templat ...
- C++ 中的模板类声明头文件和实现文件分离后,如何能实现正常编译?
著作权归作者所有. 商业转载请联系作者获得授权,非商业转载请注明出处. 作者:余天升 链接:http://www.zhihu.com/question/20630104/answer/15722407 ...
- 问模板函数、函数模板,模板类、类模板的区别的问题?
问模板函数.函数模板,模板类.类模板的区别的问题? - 赵保龙 - 博客园 问模板函数.函数模板,模板类.类模板的区别的问题? 在C++中有好几个这样的术语,但是我们很多时候用的并不正确,几乎是互相替 ...
- c++ array 模板类使用
目录 1.array模板类的定义 (1)array模板类的声明 (2)容器属性 (3)array模板类的说明 (4)array模板类头文件 2.array模板类的使用 (1)Iterators (2) ...
- 从汇编的眼光看C++(之递归函数与模板类)
[ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 递归,相信有过基本C语言经验的朋友都明白,就是函数自己调用自己.所以,本质上说,它和普通的函数 ...
- 用汇编的眼光看C++(之模板类)
[ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 如果类是一种确定的数据类型,那么模板就是一种对类的抽象.假设有这么一种类,它需要进行数据的计算 ...
- C++ 语言禁止派生类 - final specifier
C++ 语言禁止派生类 - final specifier 1. 禁止派生类 可以将类指定为 final,确保不能将类用作基类. 禁止派生 CBox 类: class CBox final {// C ...
最新文章
- oracle rac对心跳要求_关于心跳网络引起的Oracle RAC的节点驱逐(不是实例驱逐)...
- controller如何保证当前只有一个线程执行_今天我们来聊一聊 Spring 中的线程安全性...
- 柱状图添加数字标签_Python之利用Plotnine作图(一)——简单柱状图
- jquery基本操作
- Java程序员必须掌握的7个Java性能指标!
- 使用组策略推送exchange自签名证书
- iOS:Covert p12 back to CSR
- android init.rc 到底在哪里?
- 语言怎么得到直流电压并采样_热点|昆明专业12V10A开关电源怎么选
- python axis=1是行吗_Python:axis=0 axis=1的理解
- Spring Boot整合Druid的使用以及步骤
- 运用Python实现猜数字游戏
- java pgm_如何用Java读取PGM图像?
- 机器之心的进化 / 理解 AI 驱动的软件 2.0 智能革命
- 【图像分割】基于区域的重叠椭圆拟合实现细胞分割附matlab代码
- 大话数据结构(五)——栈的两种java实现方式
- Hangfire 使用笔记
- 利用JQuery实现HTML页面跳转
- 有哪些在线尺子测量工具?这个工具值得试试
- C语言中三个数排列大小,C语言三个数排列大小的实现方法
热门文章
- 0x000000f怎么修复 win10_0xc000000f怎么修复,教你u盘重装win10系统出现0xc000000f的修复方法...
- 记一次破解自己win10登录密码的经历
- Oracle SQL数字函数
- CSS样式创建(外部样式 内部样式 内联样式)
- 跟领导提辞职,领导想留你,留还是不留呢?
- 安卓手机上哪个支持语音输入的记事本软件好用?
- 【Android自动化测试】Robot Framework+adb框架(五)——L1层测试用例
- java utf 8转义_Tomcat8及以上特殊字符转义问题
- 上海亚商投顾:沪指全天窄幅震荡 大消费板块再掀涨停潮
- hive 分区表select全部数据_Hive分区表的分区操作