2010-04-21 7 views
1
#include <list> 
#include <set> 
#include <iterator> 
#include <algorithm> 

using namespace std; 

class MyContainer { 
public: 
string value; 

    MyContainer& operator=(const string& s) { 
     this->value = s; 
     return *this; 
    } 
}; 

int main() 
{ 
    list<string> strings; 
    strings.push_back("0"); 
    strings.push_back("1"); 
    strings.push_back("2"); 

    set<MyContainer> containers; 
    copy(strings.begin(), strings.end(), inserter(containers, containers.end())); 
} 

Le code précédent ne compile pas. En mode C++ standard, la sortie d'erreur est verbeuse et difficile à comprendre. La partie clé semble être ... ceC++ STL question liée à l'insertion d'itérateurs et opérateurs surchargés

/usr/include/c++/4.4/bits/stl_algobase.h:313: error: no match for ‘operator=’ in ‘__result.std::insert_iterator::operator* [with _Container = std::set, std::allocator >]() = __first.std::_List_iterator::operator* [with _Tp = std::basic_string, std::allocator >]()’

... que j'Interpet signifie que l'opérateur d'affectation nécessaire n'est pas défini. J'ai regardé le code source de insert_iterator et noté qu'il a surchargé l'opérateur d'affectation. L'algorithme de copie doit utiliser l'opérateur d'affectation surchargé d'itérateurs d'insertion pour effectuer son travail (?).

Je suppose que parce que mon itérateur d'entrée est sur un conteneur de chaînes et que mon itérateur de sortie est sur un conteneur de MyContainers que l'opérateur d'assignation insert_iterator surchargé ne peut plus fonctionner.

C'est ma meilleure estimation, mais je me trompe probablement. Alors, pourquoi cela ne fonctionne-t-il pas exactement et comment puis-je accomplir ce que j'essaie de faire?

Répondre

4

ce qui fonctionnerait serait d'utiliser le constructeur (qui aurait plus de sens au lieu de l'affectation):

class MyContainer { 
public: 
string value; 

    MyContainer(const string& s): value(s) { 
    } 
}; 

Ensuite, le deuxième problème est que cet ensemble nécessite également que son contenu soit comparable.

Quant à la cause, insert_iterator travaux par une surcharge operator=:

insert_iterator<Container>& operator= (typename Container::const_reference value); 

Comme vous pouvez le voir, la valeur de droite doit être soit le type de valeur du conteneur ou implicitement convertible, ce qui est exactement ce que le constructeur (non explicite) atteint et l'opérateur d'assignation ne le fait pas.


Techniquement, vous pouvez aussi le faire fonctionner sans changer la classe (par exemple, si vous ne voulez pas un constructeur non explicite) en fournissant une fonction de conversion appropriée:

MyContainer from_string(const std::string& s) 
{ 
    MyContainer m; 
    m = s; //or any other method how to turn a string into MyContainer 
    return m; 
} 

qui peut être utilisé avec std::transform:

transform(strings.begin(), strings.end(), inserter(containers, containers.end()), from_string); 
+0

Merci !!!!!!! – rshepherd

+0

'std :: set' a besoin de' operator <() ' – wilhelmtell

+0

Strictement parlant, ce n'est pas le cas. C'est un problème secondaire ici, et brièvement mentionné dans la réponse. – UncleBens

3

Vous devez ajouter:
1. Constructeur qui prend la chaîne (vous essayez d'ajouter une chaîne au conteneur pouvant contenir des objets MyContainer).
2. bool operator < (jeu utilise par défaut pour comparer les éléments)
Par exemple:

class MyContainer 
{ 
    public: 
    MyContainer(const string& v):value(v){}; 
}; 
bool operator <(const MyContainer &c1, const MyContainer &c2) 
{ 
return c1.value <c2.value; 
} 
1

Le problème est double:

  1. Vous essayez de remplir un ensemble d'objets MyContainer
  2. ... dans une liste d'objets string.

L'algorithme copy() tente de convertir chaque objet string à un objet MyContainer.En C++ pour ajouter au support de conversion de classe MyContainer à partir du type string taper MyContainer vous devez ajouter un constructeur qui prend un paramètre de type string:

struct MyContainer { 
    MyContainer(const string& s) : value(s) { } 
    bool operator<(const MyContainer& o) const { return value < o.value; } 

private: 
    string s; 
}; 

Vous n'avez pas besoin d'un opérateur d'affectation, car le compilateur peut obtenir la copie effectuée par le constructeur de copie: convertissez un string en MyContainer puis utilisez l'opérateur d'affectation par défaut pour affecter un objet MyContainer à l'autre. Vous aurez cependant besoin d'un operator<() car les ensembles C++ sont triés.

Questions connexes