C++14下std::conditional编译期继承与enable_if方案优化咨询
方案优化思路(适配GCC 8.1 + C++14标准)
你的核心实现思路(编译期选择互斥基类)是完全可行的,但现有写法存在不少可优化的空间,也有比成员函数级std::enable_if更简洁的实现方式。
现有写法的主要问题
- 冗余度高:每个分支专属的成员函数都要重复写一遍SFINAE约束代码,后续新增方法时每次都要复制粘贴判断逻辑,很容易写错
- 错误排查成本高:如果SFINAE约束写漏或者写错,会出现同名成员函数签名冲突,GCC 8输出的模板实例化错误栈通常有几十行,定位问题非常麻烦
- 代码可读性差:阅读成员函数时需要先看一长串enable_if判断才能知道这个方法属于哪个分支
- 示例代码存在笔误:main函数里写的
EmptyClass、NonEmptyClass和你定义的Storage类名不匹配,直接编译会报错
更优实现:分支逻辑下沉到互斥基类
既然你已经通过std::conditional保证了同一时间只会继承两个基类中的一个,完全没必要在派生类里用SFINAE筛成员函数——直接把对应分支的专属方法、成员变量全放到对应的基类里实现即可,派生类只需要保留两个分支共用的逻辑。
C++14已经提供了std::conditional_t别名模板,可以省去写typename ...::type的冗余代码,GCC 8.1完全支持这个特性。
具体实现代码如下:
#include <vector> #include <type_traits> // 分支1:A、B类型相同时的基类,实现该场景下所有专属逻辑 template<typename T> class SameTypeStorage { public: void doStuff() { // 单模板参数/两参数同类型的业务逻辑 } void doSomethingElse() { // 仅同类型场景下存在的专属方法逻辑 } }; // 分支2:A、B类型不同时的基类,实现该场景下所有专属逻辑,持有对应成员变量 template<typename T, typename U> class DifferentTypeStorage { protected: std::vector<U> mObjects; public: void doStuff() { // 两参数不同类型的业务逻辑,可以直接访问mObjects成员 } }; // 外层Storage类仅做编译期分发,不需要写任何SFINAE约束 template<typename A, typename B = A> class Storage : public std::conditional_t< std::is_same<A, B>::value, SameTypeStorage<A>, DifferentTypeStorage<A, B> > { // 这里只需要写两个分支共有的通用方法即可 }; int main() { Storage<int> emp; Storage<int, float> nonemp; emp.doStuff(); emp.doSomethingElse(); nonemp.doStuff(); // 下面这行直接编译报错,提示类没有对应成员,错误信息非常清晰 // nonemp.doSomethingElse(); }
这个实现和你原来的写法相比有几个明显优势:
- 零冗余:不需要为每个成员函数重复写SFINAE约束,同分支的逻辑全收敛到对应基类,后续新增功能直接改对应基类即可,不需要动外层分发类
- 错误提示友好:如果调用了当前分支不存在的方法,编译器会直接报“类没有该成员”的明确错误,不会输出晦涩的模板实例化栈
- 无冲突风险:两个基类是编译期互斥的,根本不会出现同名成员函数冲突的问题,后续修改方法签名也不需要担心约束写错
- 性能完全一致:所有选择逻辑都在编译期完成,没有任何额外运行时开销,和你原写法的生成代码完全等价
如果你坚持保留原写法的改进点
如果因为项目结构原因不能把逻辑下沉到基类,至少可以把重复的SFINAE判断抽成通用别名,减少冗余代码:
template<typename T, typename U> using enable_if_same = std::enable_if_t<std::is_same<T, U>::value>; template<typename T, typename U> using enable_if_diff = std::enable_if_t<!std::is_same<T, U>::value>;
成员函数的约束就可以简化成下面的写法,不用每次都写一长串:
template<typename C = B, typename = enable_if_same<C, A>> void doStuff() { /* 同类型逻辑 */ } template<typename C = B, typename = enable_if_same<C, A>> void doSomthingElse() { /* 同类型专属逻辑 */ } template<typename C = B, typename = enable_if_diff<C, A>> void doStuff() { /* 不同类型逻辑 */ }
注意C++14同样提供了std::enable_if_t别名,不需要手动写typename std::enable_if<...>::type。
内容的提问来源于stack exchange,提问作者Mountler
相关产品推荐
相关产品推荐

