2009-07-13 6 views
2

Tenir compte de la classe suivante:Existe-t-il un objet fonction pour créer des objets dans STL?

class Person { 
public: 
    // I don't want any "char *" to be converted to Person implicitly! 
    explicit Person(const char * name) : name_(name) {}; 

private: 
    std::string name_; 
}; 

Voir également tableau suivant des données char *:

char STUDENT_NAMES[][20] = { 
    "Bart", 
    "Liza", 
    "Maggie" 
}; 

Maintenant, je veux créer std :: liste de personne selon ce tableau. Tout ce que je pourrais inventer est d'utiliser std :: algorithme de transformation avec un objet de fonction écrite à la main:

struct CreatePerson : public std::unary_function<const char*,Person> { 
    Person operator() (const char * name) const { 
     return Person(name); 
    }; 
}; 

// ... 

std::list<Person> students; 
std::transform(
    &STUDENT_NAMES[ 0 ], 
    &(STUDENT_NAMES[ sizeof(STUDENT_NAMES)/sizeof(STUDENT_NAMES[0]) ]), 
    front_inserter(students), 
    CreatePerson()); 
// ... 

Y at-il plus court et/ou de façon plus claire de le faire? Peut-être certains objets de fonction standard ou des adaptateurs?

Répondre

5

Vous pouvez utiliser boost::lambda de la manière suivante:

#include <boost/lambda/lambda.hpp> 
#include <boost/lambda/construct.hpp> 
#include <string> 
#include <iterator> 
#include <algorithm> 
#include <list> 

struct person { 
    explicit person(char const *name) 
    :name(name) { } 
private: 
    std::string name; 
}; 

int main() { 
    char names[][20] = { 
    "Michael", "litb" 
    }; 

    std::list<person> v; 
    std::transform(names, names + 2, std::front_inserter(v), 
    boost::lambda::constructor<person>()); 
} 

Je ne pense pas qu'il y ait une telle façon avec la bibliothèque standard C++.

+0

J'espère que cette calcs du tableau sont en ce moment, enfin. Ignorez mes commentaires muets ce que j'avais temporaire dans ma réponse sur ce qui donne quel type. Srsly, tableau hax le matin me fait mal au cerveau :) Cependant, je vous recommande toujours de faire 'STUDENT_NAMES' un' char const * noms [] = {"Bart", "Lisa", ...}; '- de cette façon il ne peut plus dépasser la limite de 20 char. Je ne connais cependant pas votre code-base. Y avait-il une forte raison pour que vous le fassiez de cette façon? –

+0

Votre solution semble bonne, merci! A propos de la taille du tableau. Merci pour votre suggestion, mais ce n'est pas le problème. Mon exemple est sorti de son contexte et réécrit pour faciliter la compréhension. :) – Michael

+0

@litb: _const_ char names [] [20] n'entraîne aucune relocalisation des données et permet donc aux données de vivre en mémoire, comme les EPROM. OTHO, même _const_ char * names [] nécessite des relocations (c'est un tableau de pointeurs, et ces pointeurs doivent être déplacés): http://people.redhat.com/drepper/dsohowto.pdf –

0

Pas beaucoup d'aide, mais est pas là une macro standard des éléments pour

sizeof(STUDENT_NAMES)/sizeof(STUDENT_NAMES[0]) 

Recherche rapide n'a pas trouvé, mais je me sens comme toute mise en œuvre, je l'ai utilisé a. Une autre suggestion que j'ai est de transformer CreatePerson en un modèle - de cette façon, si vous en avez encore besoin, vous avez juste besoin de faire CreateObj ou quelque chose comme ça.

-1

Eh bien, je vais juste avoir écrit une méthode/fonction comme:

convert(const char*[] names, std::list<Person>&); 

Pourquoi pas si juste pour faire une conversion simple? Peut-être que le point me manque?

M2C

+0

Il s'agit de réutiliser le code d'itération défini dans la bibliothèque standard. L'en-tête 'algorithm' contient des tas de fonctions utiles pour des tâches d'itération très courantes, non limitées aux listes, aux vecteurs, aux tableaux, mais utilisant des 'itérateurs'. – xtofl

+0

@xtofl: Oui, j'accepte avec vous. Mon point est que la valeur ajoutée dans ce cas n'est pas évidente, car dans l'exemple donné, vous devez écrire une fonction unaire en dehors de votre portée de classe Person, et cela juste pour appliquer un algorithme de transformation standard. Votre solution (utilisant le constructeur) est géniale et l'utilisation de la transformation apparaît propre. Mais écrire un unaire juste pour utiliser transformer ... – neuro

2

Votre constructeur de la classe est une fonction de conversion. Vous n'avez pas besoin de transformer: vous pouvez simplement insérer. Jetez un oeil à this code here.

std::list<Person> ps(NAMES, NAMES+sizeof(NAMES)/sizeof(NAMES[0])); 

Sinon, une solution de contournement plus courte serait en utilisant une fonction d'usine statique:

struct Person { 
    static Person create(const char* name); 
    .... 
}; 

std::transform(NAMES, NAMES+sizeof(NAMES)/sizeof(NAMES[0], front_inserter(ps), 
    &Person::create); 
+0

+1 là la transformation semble beaucoup plus stylée que dans l'exemple de question ... – neuro

+0

Non, ce n'est pas le cas. Veuillez noter que mon constructeur est explicite. Deuxième exemple avec statique create() fonctionne vraiment bien, mais il est seulement agréable adoption de la mienne. Vous venez de déplacer la fonctionnalité du foncteur vers la méthode statique. Merci quand même. Ce que je voulais voir est une méthode pour créer directement mon objet. Pour l'instant il me semble, il n'y a pas une telle capacité dans STL. – Michael

+0

Vous avez totalement raison. Vous avez demandé une façon plus agréable - ne faites que légèrement: vous n'avez pas besoin du foncteur supplémentaire. – xtofl

Questions connexes