如何为带有推导指引的C++类模板提供两个完全兼容的别名?
问题根因
截至C++23标准,类模板实参推导(CTAD)仅支持真实的类模板,不支持模板别名,因此原有的using Foo = Bar<T>别名方案无法兼容Foo(17)这类依赖CTAD的调用写法。
通用兼容方案
最简单的无侵入方案是让旧名称Foo作为新类Bar的公开派生类模板,继承所有构造函数,同时补充Foo对应的推导指引即可:
template <typename T> class Bar { public: // Create a Bar from a T value. explicit Bar(T value); // 原有类的所有成员、接口保持不变 }; // 兼容用旧名称,公开继承Bar无额外开销 template <typename T> class Foo : public Bar<T> { public: // 继承Bar的全部构造函数 using Bar<T>::Bar; }; // Bar的推导指引不变 template <typename T> explicit Bar(T) -> Bar<T>; // 额外补充Foo的推导指引即可 template <typename T> explicit Foo(T) -> Foo<T>;
方案优势
- 完全兼容原有所有调用:
Foo(17)等依赖CTAD的写法可以正常编译,所有针对Foo的传参、指针/引用转换逻辑都和之前完全一致 - 无额外运行时开销:空的公开继承不会增加内存布局成本,也不会引入额外的运行时开销
- 迁移成本极低:不需要修改原有
Bar的任何实现,只需要新增十几行兼容代码即可,后续所有新功能只需要在Bar上迭代,Foo会自动继承所有能力
注意事项
- 如果原有代码存在针对
Foo的自定义模板特化,迁移过程中需要同步将特化逻辑适配到Bar,或者保留Foo的特化实现 - 若
Bar原本没有虚析构函数,不要通过Bar指针删除Foo对象,这和迁移前的编码规范要求一致,不属于方案引入的新问题
内容的提问来源于stack exchange,提问作者jacobsa
相关产品推荐
相关产品推荐

