62 votes

Comment parcourir une carte STL remplie de chaînes en C ++

J'ai le problème suivant liées à parcourir un tableau associatif des chaînes définies en utilisant std::map.

-- snip --
class something 
{
//...
   private:
      std::map<std::string, std::string> table;
//...
}

Dans le constructeur, je remplir le tableau avec des paires de clés de chaîne associée à la chaîne de données. Ailleurs, j'ai une méthode toString qui renvoie un objet de type string qui contient toutes les clés et les données associées contenues dans l'objet de la table(clé=format des données).

std::string something::toString() 
{
        std::map<std::string, std::string>::iterator iter;
        std::string* strToReturn = new std::string("");

        for (iter = table.begin(); iter != table.end(); iter++) {
           strToReturn->append(iter->first());
           strToReturn->append('=');
           strToRetunr->append(iter->second());
           //....
        }
       //...
}

Lorsque j'essaie de compiler j'ai le

erreur: "error: no match for call to ‘(std::basic_string, std::allocator >) ()'".

Quelqu'un pourrait m'expliquer ce qu'il manque, ce que je fais mal? Je n'en ai trouvé une discussion sur un problème similaire dans le cas des classes hash_map où l'utilisateur doit définir une fonction de hachage pour être en mesure d'utiliser les classes hash_map avec std::string objets. Pourrait être quelque chose de semblable aussi dans mon cas?

Merci!!!!

74voto

Tom Leys Points 10453

Votre principal problème est que vous appelez une méthode appelée first() dans l'itérateur. Ce que vous êtes censé faire est d'utiliser la propriété appelée first :

 ...append(iter->first) rather than ...append(iter->first())
 

En termes de style, vous ne devriez pas utiliser new pour créer cette chaîne.

 std::string something::toString() 
{
        std::map<std::string, std::string>::iterator iter;
        std::string strToReturn; //This is no longer on the heap

        for (iter = table.begin(); iter != table.end(); ++iter) {
           strToReturn.append(iter->first); //Not a method call
           strToReturn.append("=");
           strToReturn.append(iter->second);
           //....
           // Make sure you don't modify table here or the iterators will not work as you expect
        }
        //...
        return strToReturn;
}
 

edit: facildelembrar a souligné (dans les commentaires) que dans le C moderne, vous pouvez maintenant réécrire la boucle

 for (auto& item: table) {
    ...
}
 

19voto

Loki Astari Points 116129
  1. Ne pas écrire d' toString() méthode. Ce n'est pas Java. Mettre en œuvre l'opérateur de flux de données pour votre classe.

  2. Préférez l'utilisation de la norme des algorithmes sur la rédaction de votre propre boucle. Dans cette situation, std::for_each() fournit une interface agréable pour ce que vous voulez faire.

  3. Si vous devez utiliser une boucle, mais n'avez pas l'intention de modifier les données, préférez const_iterator sur iterator. De cette façon, si vous avez essayer et modifier les valeurs, le compilateur va vous avertir.

Alors:

std::ostream& operator<<(std::ostream& str,something const& data)
{
    data.print(str)
    return str;
}

void something::print(std::ostream& str) const
{
    std::for_each(table.begin(),table.end(),PrintData(str));
}

Ensuite, lorsque vous souhaitez imprimer, il suffit de flux de l'objet:

int main()
{
    something    bob;
    std::cout << bob;
}

Si vous avez réellement besoin d'une chaîne de la représentation de l'objet, vous pouvez ensuite utiliser lexical_cast.

int main()
{
    something    bob;

    std::string  rope = boost::lexical_cast<std::string>(bob);
}

Les détails qui doivent être remplis.

class somthing
{
    typedef std::map<std::string,std::string>    DataMap;
    struct PrintData
    {
         PrintData(std::ostream& str): m_str(str) {}
         void operator()(DataMap::value_type const& data) const
         {
             m_str << value.first << "=" << value.second << "\n";
         }
         private:  std::ostream& m_str;
    };
    DataMap    table;
    public:
        void something::print(std::ostream& str);
};

4voto

Adam Points 2333

Changez d'ajouter des appels à dire

...append(iter->first)

et

... append(iter->second)

En outre, la ligne

std::string* strToReturn = new std::string("");

alloue une chaîne sur le tas. Si vous avez l'intention de renvoyer en fait un pointeur vers cette allouée dynamiquement chaîne, le retour devrait être modifié pour std::string*.

Alternativement, si vous ne voulez pas à vous soucier de la gestion de l'objet sur le tas, changement de déclaration à

std::string strToReturn("");

et de modifier le 'append' appelle pour l'utilisation de syntaxe de référence...

strToReturn.append(...)

au lieu de

strToReturn->append(...)

Sachez que ce sera de construire la chaîne sur la pile, puis copie dans la variable de retour. Cela a des implications sur les performances.

2voto

Nick Lewis Points 3143

iter->first et iter->second sont des variables, vous essayez de les appeler en tant que méthodes.

2voto

E.M. Points 2407

Notez que le résultat de la déréférence de std :: map :: iterator est un std :: pair . Les valeurs de first et second ne sont pas des fonctions, elles sont des variables.

Changement:

 iter->first()
 

à

 iter->first
 

Idem avec iter->second .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X