7
votes

trouver un élément dans std :: vector de std :: any

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";


3 commentaires

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.


4 Réponses :


6
votes

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);
}

Démo en direct

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)


4 commentaires

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 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



0
votes

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


1 commentaires

une fois que vous utilisez std :: variant , std :: visit peut vous aider.



2
votes

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".

La

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.


0 commentaires

1
votes

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();
}


1 commentaires

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);