Boost.Icl interval_map仿函数问题:不同仿函数的容器操作方案
问题
我有一个带有特定Combine仿函数的interval_map,该仿函数在多数场景下可实现预期的合并逻辑,但有时需要不同的行为。由于Combine是模板参数,无法在运行时修改其行为。我曾考虑使用关联实现逻辑的静态单例枚举变量,但全局变量通常不是好方案,且若map声明在头文件中,该方案也无法生效。
于是我转而使用带有不同仿函数的map来处理特殊场景,示例代码如下:
#include <iostream> #include <boost/icl/interval_map.hpp> using namespace boost::icl; template <class Type> struct inplace_replace : boost::icl::identity_based_inplace_combine<Type> { void operator()(Type& object, const Type& operand) const { object = operand; } }; template <class Type> struct inplace_toggle : boost::icl::identity_based_inplace_combine<Type> { typedef identity_based_inplace_combine<Type> base_type; void operator()(Type& object, const Type& operand) const { if (object == operand) object = base_type::identity_element(); else object = operand; } }; int main() { interval_map<int, int, partial_absorber, std::less, inplace_replace> imap; interval_map<int, int, partial_absorber, std::less, inplace_toggle> toggler; imap += make_pair(interval<int>::right_open(0, 4), 2); imap += make_pair(interval<int>::right_open(6, 8), 1); toggler += make_pair(interval<int>::right_open(2, 10), 2); toggler += imap; imap.clear(); for (auto& v : toggler) imap += v; std::cout << imap << std::endl << toggler; }
该方案存在问题:不仅需要创建第二个map,且由于两者模板参数(仿函数)不同,无法使用移动语义将结果转移到原map中,只能采用复制方式。
我的问题是:
- 是否存在方法可在带有不同仿函数的map间执行移动操作?
- 有没有比全局变量更好的方式来调整仿函数的行为?
或许我遗漏了定制区间容器的通用思路,但目前该问题颇具挑战性。
回答
问题1:不同Combine仿函数的interval_map间的移动操作
直接移动是做不到的。因为interval_map的模板参数包含Combine仿函数,这意味着两种interval_map是完全不同的类型,C++不允许不同类型之间的移动构造或赋值。
不过可以尝试以下方式降低拷贝开销:
- 复用处理后的容器:完成特殊逻辑后,直接使用
toggler作为后续操作的容器,避免将数据移回原imap,从根源上消除拷贝需求。 - 操作底层存储(不推荐):如果Boost.ICL的
interval_map暴露了底层存储容器(比如内部的std::map),可以通过交换底层容器的方式转移数据。例如:
这种方式属于对实现细节的依赖,违反封装原则,跨版本兼容性差,不建议在生产代码中使用。// 假设interval_map内部有私有成员map_存储数据,需结合Boost源码确认 std::swap(imap.map_, toggler.map_);
问题2:替代全局变量的仿函数行为调整方案
可以通过带状态的Combine仿函数或策略模式实现行为调整,避免全局变量的弊端:
方案1:编译时可配置的仿函数模板
通过模板参数固定行为,适合不需要运行时切换的场景:
template <class Type, bool IsToggle> struct adaptive_combine : boost::icl::identity_based_inplace_combine<Type> { void operator()(Type& object, const Type& operand) const { if constexpr(IsToggle) { if (object == operand) object = this->identity_element(); else object = operand; } else { object = operand; } } };
使用时通过模板参数切换行为:
// 替换模式 interval_map<int, int, partial_absorber, std::less, adaptive_combine<int, false>> imap_replace; // 切换模式 interval_map<int, int, partial_absorber, std::less, adaptive_combine<int, true>> imap_toggle;
方案2:运行时可切换状态的仿函数
将状态封装在仿函数内部,支持运行时动态调整行为:
template <class Type> struct runtime_combine : boost::icl::identity_based_inplace_combine<Type> { enum class Mode { Replace, Toggle }; static inline std::atomic<Mode> current_mode = Mode::Replace; // 原子变量保证线程安全 static void set_mode(Mode m) { current_mode.store(m); } void operator()(Type& object, const Type& operand) const { switch(current_mode.load()) { case Mode::Replace: object = operand; break; case Mode::Toggle: if (object == operand) object = this->identity_element(); else object = operand; break; } } };
使用时通过静态成员函数切换模式:
runtime_combine<int>::set_mode(runtime_combine<int>::Mode::Toggle);
方案3:策略模式封装多行为
定义抽象策略基类,将不同合并逻辑封装为具体策略,通过切换策略实例实现行为调整:
template <class Type> struct combine_strategy : boost::icl::identity_based_inplace_combine<Type> { virtual void operator()(Type&, const Type&) const = 0; }; template <class Type> struct replace_strategy : combine_strategy<Type> { void operator()(Type& object, const Type& operand) const override { object = operand; } }; template <class Type> struct toggle_strategy : combine_strategy<Type> { void operator()(Type& object, const Type& operand) const override { if (object == operand) object = this->identity_element(); else object = operand; } }; template <class Type> struct combined_combine : boost::icl::identity_based_inplace_combine<Type> { std::shared_ptr<const combine_strategy<Type>> strategy_; combined_combine() : strategy_(std::make_shared<replace_strategy<Type>>()) {} explicit combined_combine(std::shared_ptr<const combine_strategy<Type>> s) : strategy_(s) {} void operator()(Type& object, const Type& operand) const { (*strategy_)(object, operand); } void set_strategy(std::shared_ptr<const combine_strategy<Type>> s) { strategy_ = s; } };
这种方式完全支持运行时灵活切换行为,且通过智能指针管理策略对象,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Rabter
相关产品推荐
相关产品推荐

