如何重载方法以接受const或non-const参数且避免代码重复
如何重载方法以接受const或non-const参数且避免代码重复
嘿,这个问题我太熟了——当你需要让方法同时支持const和非const的容器参数时,最烦的就是不想把一模一样的遍历逻辑写两遍。咱们来搞定它,既满足类型安全,又不重复代码。
首先,先看你的原始实现:现在的following方法只能接受非const的unordered_map,而且返回的是Foo*的vector。但如果碰到const的map,或者你需要返回const指针的vector时,这个方法就不够用了。直接写两个几乎一样的重载肯定不是最优解,咱们用模板提取核心逻辑的方式来解决。
第一步:把核心遍历逻辑抽成私有模板函数
我们可以写一个模板函数,它能处理任意类型的map(const或非const),然后根据传入的map类型自动推导返回的指针类型。把它设为私有,因为这只是实现细节,不需要对外暴露:
class Foo { int* next; // 其他字段、方法... // 核心实现:模板函数处理不同类型的map template <typename MapType> auto following_impl(MapType& foos) const -> std::vector< typename std::conditional< std::is_const_v<std::remove_reference_t<MapType>>, const Foo*, Foo* >::type > { // 根据MapType是否为const,决定返回的指针类型 using ResultPtr = typename std::conditional< std::is_const_v<std::remove_reference_t<MapType>>, const Foo*, Foo* >::type; std::vector<ResultPtr> result; const Foo* current = this; while (current->next) { auto nextIt = foos.find(*current->next); if (nextIt == foos.end()) break; // 这里会自动匹配const或非const的指针类型 result.push_back(&nextIt->second); current = &nextIt->second; } return result; } public: // 接下来写两个public的重载方法... };
第二步:提供两个public重载接口
现在只需要写两个非常简短的public方法,分别对应const和非const的map参数,它们都会调用上面的模板实现:
// 非const版本:接受非const map,返回Foo*的vector std::vector<Foo*> following(std::unordered_map<int, Foo>& foos) { return following_impl(foos); } // const版本:接受const map,返回const Foo*的vector std::vector<const Foo*> following(const std::unordered_map<int, Foo>& foos) const { return following_impl(foos); }
为什么这么做?
- 避免代码重复:所有的遍历、查找逻辑都只在
following_impl里写一遍,两个重载只是做类型适配。 - 类型安全:传入const map时,自动返回const指针的vector,不会出现意外的可修改指针;传入非const map时,返回可修改的指针,符合预期。
- 兼容性:如果用的是C++14,把
std::is_const_v换成std::is_const<typename std::remove_reference<MapType>::type>::value,std::remove_reference_t换成typename std::remove_reference<MapType>::type就行,同样能正常工作。
使用示例
// 非const容器场景 std::unordered_map<int, Foo> foos; // 填充foos... Foo& myFoo = foos[1]; std::vector<Foo*> nonConstFollowers = myFoo.following(foos); // const容器场景 const std::unordered_map<int, Foo>& constFoos = foos; const Foo& constMyFoo = constFoos.at(1); std::vector<const Foo*> constFollowers = constMyFoo.following(constFoos);
这样不管你手里是const还是非const的map,都能调用对应的following方法,而且完全不用重复写遍历代码,完美解决你的问题!
备注:内容来源于stack exchange,提问作者Bruce Nielsen
相关产品推荐
相关产品推荐

