J'ai besoin d'un objet qui peut encapsuler une initialisation paresseuse pour un try_emplace avec map (en effet, appeler une fonction de type usine uniquement lorsque cela est nécessaire), de sorte que ce qui suit convertira ok en try_emplace
:
std::map<std::string, whatever_wrapper<bool> > cache_; cache_.try_emplace("hello", []{return true;});
ou peut-être
std::map<std::string, bool> cache_; cache_.try_emplace("hello", lazy_wrapper([]{return true;}));
J'imagine que cela devrait être possible, mais principalement à la recherche d'un solution standard (par exemple, std
/ boost
) par rapport au roulage de mon propre wrapper.
3 Réponses :
Ce qui suit est une solution faite à la main que je viens de mettre en place en quelques minutes, qui fait le travail, mais je suis surtout à la recherche d'une sorte de solution standard:
template<class F> struct lazy_wrap { F f_; lazy_wrap(F&& f) : f_(f) {} template<class T> operator T() { return f_(); } };
Cela évaluera f
à chaque fois pour obtenir un T
, je n'appellerais pas ça "paresseux"
Oh, c'est pour std :: map
, pas pour std :: map
Avez-vous vraiment besoin d'un wrapper? Vous pouvez le faire à la place:
// 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, clair, pas de mal de tête.
cela fait une double recherche
Je n'ai pas vraiment besoin i> un wrapper comme vous dites (map.find fonctionne aussi) - mais il est plus expressif de cette façon avec une ligne de code. Sur le même token, nous ne I> besoin i> try_emplace en premier lieu.
Vous devrez finalement implémenter la logique try-emplace vous-même, car il n'y a pas de fonction simple pour le faire.
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); }
Oui, cela recherche l'élément deux fois, mais il n'y a aucun moyen de le faire. évitez cela sans faire partie de l'implémentation de std :: map
(c'est pourquoi try_emplace
existe). Le temps de recherche peut être réduit en remplaçant map.find
par map.lower_bound
, en modifiant le test conditionnel pour voir si la clé n'est pas égale à clé
, et en utilisant emplace_hint
avec cet itérateur.
Qu'as-tu essayé?
J'ai essayé de fournir le lambda nu, celui ofc. n'a pas compilé. Je suppose qu'il est assez facile de créer un type de classe qui sera converti, mais comme je l'ai dit, je suis surtout intéressé si une solution standard existe déjà.
Hélas dans un monde (de transmission) parfait; P0927R0: Vers A (paresseux) Mécanisme de transfert pour C ++ .
En termes de paresse, voulez-vous dire que la fonction n'est pas appelée à moins que la clé ne soit pas présente dans la carte?
@NicolBolas c'est correct