C++98中简化大量模板关键字及cell相关代码的方法问询
Hey, great question! 你遇到的这个场景太典型了——用了模板类cell<T>但绝大多数时候根本碰不到T* someInfo这个模板相关成员,结果代码里全是template<typename T>、cell<T>,搞得刚接触C++的人看得头大。咱们分两种思路来解决,兼顾可读性和你的需求:
一、C++98下无宏的“伪类C”写法(保留类型安全)
遗憾的是,C98没有自动推导模板参数或者让编译器隐式把cell当成cell<T>的语法(这种便利要等到C11以后的模板别名、自动类型推导才会有),不过我们可以用非模板基类+继承的方式大幅减少冗余,同时还能保留C++的类型安全:
- 先抽离出一个非模板的基类,把所有和
T无关的成员、方法都放进去:
struct CellBase { int nr; // 所有不需要用到T的成员、函数都可以放在这里 };
- 让原模板类
cell<T>继承这个基类:
template<typename T> struct cell : public CellBase { T* someInfo; // 只有这个和模板参数相关的成员留在子类里 };
- 接下来,那些不需要操作
someInfo的函数,直接用CellBase作为参数就行——完全不用写模板!
void doSomething(CellBase c) { cout << c.nr; }
这样一来,绝大多数代码都和普通C结构体的写法一模一样,不熟悉C++的人一眼就能看懂。只有少数需要处理someInfo的函数,才需要写成模板函数:
template<typename T> void freeCellInfo(cell<T> c) { delete c.someInfo; }
这个方案的核心是把“通用部分”和“模板相关部分”拆分,既减少了冗余,又没丢类型安全,也完全不用宏,完美符合你的要求。
二、纯C风格方案(用
void*,彻底消除模板) 如果你觉得上面的方案还是有一点点C++痕迹,或者更倾向于完全类C的简洁写法,那用void*替代T*确实是最直接的选择:
- 定义一个普通的C风格结构体:
typedef struct { int nr; void* someInfo; } cell;
- 所有操作
cell的函数都不用模板,直接写普通函数就行:
void doSomething(cell c) { cout << c.nr; }
- 关于内存释放的问题:你提到只能用
free()而不能用delete,这里要注意一个坑——如果someInfo是用new分配的,直接用free()会导致未定义行为!解决这个问题有两种办法:- 统一用
malloc()分配someInfo,这样用free()释放就完全没问题; - 或者给
cell加一个释放回调函数,兼顾new和malloc的场景:
这样既保留了C风格的简洁,又能正确释放用// 定义释放函数的类型 typedef void (*FreeFunc)(void*); typedef struct { int nr; void* someInfo; FreeFunc freeFunc; // 存储对应的释放函数 } cell; // 包装delete的回调(只在分配时用到一次模板) template<typename T> void deleteWrapper(void* ptr) { delete static_cast<T*>(ptr); } // 创建cell的辅助函数(分配时指定释放方式) template<typename T> cell createCell(int nr, T* info) { cell c; c.nr = nr; c.someInfo = info; c.freeFunc = &deleteWrapper<T>; return c; } // 统一释放函数 void freeCell(cell c) { if (c.freeFunc && c.someInfo) { c.freeFunc(c.someInfo); } }new分配的内存,不用让调用者操心释放细节。
- 统一用
总结
- 如果想保留C的类型安全,同时大幅减少模板冗余,非模板基类继承是C98里最优的无宏方案;
- 如果彻底追求类C的可读性,不怕丢失类型安全,那
void*方案最直接,只要注意内存分配和释放的一致性就行。
内容的提问来源于stack exchange,提问作者Daniel Porumbel
相关产品推荐
相关产品推荐

