用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语言实现模板类的一些个人思路相关推荐

  1. 【C++ 语言】面向对象 ( 模板编程 | 函数模板 | 类模板 )

    文章目录 函数模板 类模板 代码示例 函数模板 1. 模板编程 : 类似于 Java 中的泛型编程 ; ① 函数模板 : 对应着 Java 中的泛型方法 ; ② 类模板 : 对应 Java 中的泛型类 ...

  2. 《C++语言基础》实践参考——复数模板类

    返回:贺老师课程教学链接 [项目6-复数模板类]     阅读教材例10.1.该例实现了一个复数类,但是美中不足的是,复数类的实部和虚部都固定只能是double型的.可以通过模板类的技术手段,设计Co ...

  3. Xamarin XAML语言教程模板页面TemplatedPage

    Xamarin XAML语言教程模板页面TemplatedPage 模板页面TemplatedPage 在上文中我们提到了TemplatedPage,它被称为模板页面,用来显示控件模版.Templat ...

  4. C++ 中的模板类声明头文件和实现文件分离后,如何能实现正常编译?

    著作权归作者所有. 商业转载请联系作者获得授权,非商业转载请注明出处. 作者:余天升 链接:http://www.zhihu.com/question/20630104/answer/15722407 ...

  5. 问模板函数、函数模板,模板类、类模板的区别的问题?

    问模板函数.函数模板,模板类.类模板的区别的问题? - 赵保龙 - 博客园 问模板函数.函数模板,模板类.类模板的区别的问题? 在C++中有好几个这样的术语,但是我们很多时候用的并不正确,几乎是互相替 ...

  6. c++ array 模板类使用

    目录 1.array模板类的定义 (1)array模板类的声明 (2)容器属性 (3)array模板类的说明 (4)array模板类头文件 2.array模板类的使用 (1)Iterators (2) ...

  7. 从汇编的眼光看C++(之递归函数与模板类)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 递归,相信有过基本C语言经验的朋友都明白,就是函数自己调用自己.所以,本质上说,它和普通的函数 ...

  8. 用汇编的眼光看C++(之模板类)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 如果类是一种确定的数据类型,那么模板就是一种对类的抽象.假设有这么一种类,它需要进行数据的计算 ...

  9. C++ 语言禁止派生类 - final specifier

    C++ 语言禁止派生类 - final specifier 1. 禁止派生类 可以将类指定为 final,确保不能将类用作基类. 禁止派生 CBox 类: class CBox final {// C ...

最新文章

  1. oracle rac对心跳要求_关于心跳网络引起的Oracle RAC的节点驱逐(不是实例驱逐)...
  2. controller如何保证当前只有一个线程执行_今天我们来聊一聊 Spring 中的线程安全性...
  3. 柱状图添加数字标签_Python之利用Plotnine作图(一)——简单柱状图
  4. jquery基本操作
  5. Java程序员必须掌握的7个Java性能指标!
  6. 使用组策略推送exchange自签名证书
  7. iOS:Covert p12 back to CSR
  8. android init.rc 到底在哪里?
  9. 语言怎么得到直流电压并采样_热点|昆明专业12V10A开关电源怎么选
  10. python axis=1是行吗_Python:axis=0 axis=1的理解
  11. Spring Boot整合Druid的使用以及步骤
  12. 运用Python实现猜数字游戏
  13. java pgm_如何用Java读取PGM图像?
  14. 机器之心的进化 / 理解 AI 驱动的软件 2.0 智能革命
  15. 【图像分割】基于区域的重叠椭圆拟合实现细胞分割附matlab代码
  16. 大话数据结构(五)——栈的两种java实现方式
  17. Hangfire 使用笔记
  18. 利用JQuery实现HTML页面跳转
  19. 有哪些在线尺子测量工具?这个工具值得试试
  20. C语言中三个数排列大小,C语言三个数排列大小的实现方法

热门文章

  1. 0x000000f怎么修复 win10_0xc000000f怎么修复,教你u盘重装win10系统出现0xc000000f的修复方法...
  2. 记一次破解自己win10登录密码的经历
  3. Oracle SQL数字函数
  4. CSS样式创建(外部样式 内部样式 内联样式)
  5. 跟领导提辞职,领导想留你,留还是不留呢?
  6. 安卓手机上哪个支持语音输入的记事本软件好用?
  7. 【Android自动化测试】Robot Framework+adb框架(五)——L1层测试用例
  8. java utf 8转义_Tomcat8及以上特殊字符转义问题
  9. 上海亚商投顾:沪指全天窄幅震荡 大消费板块再掀涨停潮
  10. hive 分区表select全部数据_Hive分区表的分区操作