Je veux vérifier si un élément existe ou non dans le vecteur. Je sais que le morceau de code ci-dessous le vérifiera.
bool isItemPresentInAnyVector(std::vector<std::any> items, std::any item) { for (const auto& it : items) { if (it.type() == typeid(std::string) && item.type() == typeid(std::string)) { std::string strVecItem = std::any_cast<std::string>(it); std::string strItem = std::any_cast<std::string>(item); if (strVecItem.compare(strItem) == 0) return true; } else if (it.type() == typeid(int) && item.type() == typeid(int)) { int iVecItem = std::any_cast<int>(it); int iItem = std::any_cast<int>(item); if (iVecItem == iItem) return true; } else if (it.type() == typeid(float) && item.type() == typeid(float)) { float fVecItem = std::any_cast<float>(it); float fItem = std::any_cast<float>(item); if (fVecItem == fItem) return true; } } return false; }
Mais j'ai le vecteur de n'importe quel type. c'est-à-dire std::vector<:any>
Je pousse des éléments dans le vecteur comme ceci.
std::vector<std::any> temp; temp.emplace_back(std::string("A")); temp.emplace_back(10); temp.emplace_back(3.14f);
Je dois donc trouver si la chaîne "A" est présente dans le vecteur ou non. Est-ce que std :: peut trouver de l'aide ici?
À partir de maintenant, j'utilise le morceau de code ci-dessous pour faire cela
#include <algorithm> if ( std::find(vector.begin(), vector.end(), item) != vector.end() ) std::cout << "found"; else std::cout << "not found";
4 Réponses :
Cela devrait fonctionner correctement, je suppose:
#include <vector> #include <string> #include <any> #include <algorithm> #include <iostream> auto any_compare = [](const auto &i){ return [i] (const auto &val){ return typeid(i) == val.type() && std::any_cast<decltype(i)>(val) == i; }; }; int main(){ std::vector<std::any> temp; temp.emplace_back(std::string("A")); temp.emplace_back(10); temp.emplace_back(3.14f); //int i = 10; std::string i = "A"; auto found = std::find_if(temp.begin(), temp.end(), any_compare(i)); std::cout << std::any_cast<decltype(i)>(*found); }
Ou pour rendre le code un peu plus générique et réutilisable:
#include <vector> #include <string> #include <any> #include <algorithm> #include <iostream> int main(){ std::vector<std::any> temp; temp.emplace_back(std::string("A")); temp.emplace_back(10); temp.emplace_back(3.14f); int i = 10;//you can use any type for i variable and it should work fine //std::string i = "A"; auto found = std::find_if(temp.begin(), temp.end(), [i](const auto &a){ return typeid(i) == a.type() && std::any_cast<decltype(i)>(a) == i; } ); std::cout << std::any_cast<decltype(i)>(*found); }
Remarque importante: cela est garanti pour fonctionner uniquement dans une seule unité de traduction en raison de exigences stadard sur le type std :: any
(par exemple, les mêmes types n'ont pas besoin d'avoir le même identifiant de type dans différentes unités de traduction)
Notez que std :: find_if (temp.begin (), temp.end (), any_compare (temp [0]))
échouerait ( any
de any
).
@ Jarod42 par souci de simplicité, je l'ai omis, mais je peux le réparer
@bartop: Je dirais que trouver un any
dans un vecteur de any
en utilisant un opérateur égal est impossible par conception (portatif). Cela peut être fait en implémentant std :: any
différemment, mais je ne vois pas comment vous pouvez finir par appeler la comparaison d'égalité dans une unité de compilation qui n'a jamais vu les types enveloppés dans le any code> objet si le "gestionnaire" gérant la distribution virtuelle ne prend pas en charge cette opération explicitement (et g ++ ne le fait pas car le standard ne l'exige pas).
@ 6502 vous avez raison, cela ne fonctionnera qu'avec une seule unité de compilation
Si les types sont int
, float
et string
(ou un ensemble limité de types), vous pouvez utiliser une combinaison de std :: variant
et std :: get_if
pour réaliser ce que vous voulez faire de manière simple:
std :: get_if
consiste à déterminer lequel des types est stocké dans le std::variant
.
Un exemple minimal:
#include <iostream> #include <vector> #include <string> #include <variant> int main(){ std::vector<std::variant<int, float, std::string>> temp; temp.emplace_back(std::string("A")); temp.emplace_back(10); temp.emplace_back(3.14f); for (const auto& var: temp) { if(std::get_if<std::string>(&var)) { if(std::get<std::string>(var) == "A") std::cout << "found string\n"; } if(std::get_if<int>(&var)) { if(std::get<int>(var) == 10) std::cout << "found int\n"; } if(std::get_if<float>(&var)) { if(std::get<float>(var) == 3.14f) std::cout << "found float\n"; } } }
Démo en direct
une fois que vous utilisez std :: variant
, std :: visit
peut vous aider.
Malheureusement, si vous voulez trouver une instance std :: any
dans un vecteur d'instances std :: any
, la réponse est non.
std :: any
a besoin d'un peu de "magie" par exemple pour pouvoir gérer la création de types d'objets inconnus mais cette machine est privée et ne doit prendre en charge que la création d'objet et non la comparaison d'égalité.
/ p>
Il serait possible d'implémenter ce que vous recherchez en utilisant la même approche, mais pas avec le standard std :: any
qui ne publie pas les détails nécessaires. Le modèle "manager" doit énumérer toutes les opérations possibles et, par exemple, dans l'implémentation g ++, elles sont "access", "get_type_info", "clone", "destroy", "xfer".
variante
est complètement différente, car elle répertorie explicitement tous les types autorisés et donc à tout endroit où elle est utilisée peut accéder à toutes les méthodes.
Utiliser un any
dans ce genre de but n'est pas une bonne utilisation de any
. La meilleure façon de procéder est simplement d'utiliser une variante
- puisque vous avez un ensemble fermé de types:
using V = std::variant<int, float, std::string> bool isItemPresentInAnyVector(std::vector<V> const& items, V const& item) { return std::find(items.begin(), items.end(), item) != items.end(); }
En fait, c'est encore mieux, car comme le souligne Kilian, operator == code>
fonctionne déjà exactement comme ceci:
struct Equals { template <typename T> constexpr bool operator()(T const& a, T const& b) const { return a == b; } template <typename T, typename U> constexpr bool operator()(T const& a, U const& b) const { return false; } }; using V = std::variant<int, float, std::string> bool isItemPresentInAnyVector(std::vector<V> const& items, V const& item) { auto it = std::find_if(items.begin(), items.end(), [&](V const& elem){ return std::visit(Equals{}, elem, item); }); return it != items.end(); }
Dans ce cas, vous pouvez même utiliser l'opérateur de variantes == en.cppreference.com/ w / cpp / utilitaire / variante / operator_cmp . auto it = std :: find (items.begin (), items.end (), item);
Lisez
std :: find_if
.Avez-vous envisagé d'utiliser à la place
std :: variant
?std :: find
fonctionnera bien là-dessus.Les comparaisons génériques de std :: any nécessiteraient le support de any lui-même (puisque vous ne pouvez pas any_cast basé sur type (), qui n'est pas connu au moment de la compilation); Pour ce que vous semblez faire, la variante est en effet meilleure sur plusieurs dimensions - pas de surcharge supplémentaire, pas de répartition virtuelle cachée, etc.