能否用std::variant和std::visit替换C++遗留代码的属性访问分发逻辑?
答案
完全可以实现,而且可以满足无需宏即可扩展访问其他属性的需求,具体实现方案如下:
第一步:定义通用类型转换工具(仅需实现一次,无需修改任何遗留代码)
#include <variant> #include <utility> using ObjVariant = std::variant<A*, B*, C*>; // 全局仅需写一次switch完成类型分发转换,所有属性访问复用 ObjVariant to_variant(int id) { switch (objs[id]->type) { case Type::A: return getA(id); case Type::B: return getB(id); case Type::C: return getC(id); } std::unreachable(); // C++23以上可用,低版本可替换为断言/异常处理,合法输入不会走到该分支 }
注意:该实现要求编译器支持C++17及以上标准,匹配std::variant的最低版本要求。
第二步:替换prop1ref的switch逻辑为std::visit
int& prop1ref(int id) { return std::visit([](auto* obj) -> int& { return obj->prop1; }, to_variant(id)); }
扩展访问其他属性的方法(无需宏、无需新增switch)
后续要访问prop2、prop3等其他属性时,仅需要新增对应访问函数即可,无需重复写分发逻辑:
// 访问double类型的prop2 double& prop2ref(int id) { return std::visit([](auto* obj) -> double& { return obj->prop2; }, to_variant(id)); } // 访问std::string类型的prop3 std::string& prop3ref(int id) { return std::visit([](auto* obj) -> std::string& { return obj->prop3; }, to_variant(id)); }
方案说明
- 类型转换的switch仅需要写一次,所有属性访问复用该逻辑,避免了原来每个属性都要写switch的重复代码,降低漏写case的出错概率
- 泛型lambda由编译器自动为A/B/C三个类型生成对应访问代码,会自动处理不同类型的属性内存偏移计算,完全符合题目给出的属性偏移不同但类型转换安全的前提
- 所有实现均不修改原有不可修改的遗留C++代码,符合约束要求
内容的提问来源于stack exchange,提问作者Rvd Boston
相关产品推荐
相关产品推荐

