我需要一个对象,它可以用map包装try_emplace的惰性初始化(实际上只在需要时调用工厂类型的函数),这样下面的对象将在try_emplace
中转换ok:
std::map<std::string, bool> cache_;
cache_.try_emplace("hello", lazy_wrapper([]{return true;}));
或者也许
std::map<std::string, whatever_wrapper<bool> > cache_;
cache_.try_emplace("hello", []{return true;});
我认为这应该是可能的,但主要是为了寻找现成的解决方案(例如std
/boost
),而不是滚动我自己的包装器。
以下是我在几分钟内拼凑出来的一个手工解决方案,它完成了任务,但我主要是在寻找某种现成的解决方案:
template<class F>
struct lazy_wrap {
F& f_;
lazy_wrap(F& f) : f_(f) {}
template<class T>
operator T() {
return f_();
}
};
您最终将不得不自己实现try-emplace逻辑,因为没有简单的函数来实现它。
template<typename Map, typename Key, typename Func>
auto lazy_try_emplace(Map &map, const Key &key, Func f)
{
auto it = map.find(key);
if(it == map.end())
return map.emplace(key, f());
return std::pair(it, false);
}
是的,这会查找元素两次,但是如果不是std::map
实现的一部分(这就是try_emplace
存在的原因),就无法避免这种情况。 通过将map.find
替换为map.lower_bound
,更改条件测试以查看键是否不等于key
,并将emplace_hint
与该迭代器一起使用,可以最小化搜索时间。
你真的需要包装纸吗? 您可以这样做:
// C++20
if (!cache_.contains("hello"))
cache_.emplace("hello", [] { return true; });
// pre C++20
if (cache_.count("hello") == 0)
cache_.emplace("hello", [] { return true; });
简单明了,没有头痛。