Im in need of an object that can wrap a lazy initialization for a try_emplace with map (in effect calling a factory type of function only when needed), so that the following will convert ok in try_emplace
:
std::map<std::string, bool> cache_;
cache_.try_emplace("hello", lazy_wrapper([]{return true;}));
or perhaps
std::map<std::string, whatever_wrapper<bool> > cache_;
cache_.try_emplace("hello", []{return true;});
I imagine that should be possible, but mainly on the lookout for an off-the-shelf solution (eg. std
/ boost
) compared to rolling my own wrapper.
The following is a hand-made solution i just threw together in a few minutes, that does the job, but Im mostly on the lookout for some kind of off-the-shelf solution:
template<class F>
struct lazy_wrap {
F f_;
lazy_wrap(F&& f) : f_(f) {}
template<class T>
operator T() {
return f_();
}
};
You ultimately will have to implement the try-emplace logic yourself, since there's no simple function to do it.
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);
}
Yes, this looks up the element twice, but there's no way to avoid that without actually being part of the std::map
implementation (which is why try_emplace
exists at all). Search time could be minimized by replacing map.find
with map.lower_bound
, changing the conditional test to see if the key is not equal to key
, and using emplace_hint
with that iterator.
Do you really need a wrapper? You could do this instead:
// C++20
if (!cache_.contains("hello"))
cache_.emplace("hello", [] { return true; });
// pre C++20
if (cache_.count("hello") == 0)
cache_.emplace("hello", [] { return true; });
Simple, clear, no headache.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.