如何简化基于C++模板实现的二进制数据包解析器的冗余API?
优化方案
方案1:C++17及以上版本使用类模板实参推导(CTAD)
这是最简洁的解决方案,C++17引入的类模板实参推导可以直接从构造函数入参推导模板参数,无需手动声明:
首先不需要修改你现有的ValueField和PacketParser的核心实现,只需要为PacketParser补充一条推导指引:
// 加在PacketParser定义后面即可 template <typename... Fields> PacketParser(Fields...) -> PacketParser<Fields...>;
使用时代码可以简化为:
// 完全不需要写decltype和手动指定模板参数 ValueField myField1(&MyStruct::setValue1); ValueField myField2(&MyStruct::setValue2); ValueField myField3(&MyStruct::setValue3); PacketParser myParser(myField1, myField2, myField3);
编译器会自动推导所有模板参数,没有任何冗余代码。
方案2:兼容C11/C14的辅助工厂函数
如果需要兼容旧标准,可以利用函数模板参数自动推导的特性,编写辅助创建函数避免手动写模板参数:
首先新增两个工厂函数:
// 创建ValueField的工厂函数 template <typename T, typename SetterType> ValueField<T, SetterType> make_value_field(SetterType setter) { return ValueField<T, SetterType>(setter); } // 创建PacketParser的工厂函数 template <typename... Fields> PacketParser<Fields...> make_packet_parser(Fields... fields) { return PacketParser<Fields...>(fields...); }
使用时用auto接收返回值,完全不需要写decltype:
auto myField1 = make_value_field<int>(&MyStruct::setValue1); auto myField2 = make_value_field<int>(&MyStruct::setValue2); auto myField3 = make_value_field<int>(&MyStruct::setValue3); auto myParser = make_packet_parser(myField1, myField2, myField3);
代码量比原有写法减少一半以上,也符合你原型开发的需求。
可选优化:类型擦除简化模板参数
如果不介意极小的运行时开销(原型阶段完全可以忽略),可以用std::function擦除Setter的类型,让ValueField的模板参数只保留值类型和目标结构体类型:
template <typename T, typename Target> struct ValueField { std::function<void(Target&, T)> setter; ValueField(std::function<void(Target&, T)> s) : setter(std::move(s)) {} };
使用时不需要任何推导,直接声明即可:
ValueField<int, MyStruct> myField1(&MyStruct::setValue1);
内容的提问来源于stack exchange,提问作者VincentDM
相关产品推荐
相关产品推荐

