Que pensez-vous de ce code de serialization ?

Le
Alexis Guillaume
Bonjour à tous.

Je pars d'un cas d'utilisation classique : on lit des valeurs
textuelles dans un fichier (std::string) et on les convertit en
entiers lors de l'éxécution du programme C++ (int, ou type enum).
L'opération inverse doit se faire bien sûr lors de l'écriture du
fichier.
Comme on aime les template en C++, supposons que T soit le type stocké
dans les fichiers et U le type stocké dans le programme utilisateur.

Un tel cas oblige bien à faire, à un moment ou à un autre, deux
fonctions de correspondance dans le programme C++ : l'une de T à U,
l'autre de U à T. On peut bien sûr les faire à base de if/else, mais
on préfère tout de même utiliser des tables de correspondances, par
exemple de type std::map pour une meilleure efficacité.

Déclarer en dur le contenu de std::map peut être assez pénible.
Surtout que dans notre cas il y en deux au contenu quasiment identique
pour un être humain mais très différent pour le compilateur puisque la=

première est de type std::map<T, U> et la seconde std::map<U, T>.
J'ai donc écrit la classe template serializer_generique qui automatise
tout ce travail. Il suffit à l'utilisateur de déclarer un tableau
constant de std::pair< T, U > ; à partir d'un tel tableau, cette
classe va construire les deux std::map nécessaires pour faire les
conversions. On imagine bien sûr que les objets de cette classe ne
serviront que lors de l'initialisation du programme.

J'aimerais soumettre mon code aux membres de ce forum afin de récolter
des critiques qui me feront progresser. Oui je demande en quelque
sorte une revue de code gratuite ;-) mais il me semble que cela ne
déplaira pas à certains ici !
Je voudrais en fait savoir :
* En quoi mon code réinvente la roue (car je parierais bien que c'est
le cas) ;
* Si mon idée de départ est bonne, s'il y en a des meilleurs, etc
* En supposant que cette idée soit bonne, quelle est la qualité de ce
code ?

Sans plus attendre, voici le code source, qui compile avec gcc 4.2.3 :

#include <map>
#include <iostream>
#include <algorithm>
#include <iterator>

template <typename T, typename U, int size>
class serializer_generique {
struct inverse_paire_iterateur {
private:
typedef std::pair< T, U > type_entree;
typedef std::pair< U, T > type_sortie;
std::pair< T, U > const *const m_tab;
unsigned int m_pos;
public:
inverse_paire_iterateur( type_entree const in[size], unsigned int p
= 0 ) :
m_tab( in ),
m_pos( p )
{
}
type_sortie operator *() {
return type_sortie( m_tab[m_pos].second, m_tab[m_pos].first );
}
inverse_paire_iterateur & operator ++() {
++m_pos;
return *this;
}
inverse_paire_iterateur operator ++( int ) {
inverse_paire_iterateur copy( *this );
++m_pos;
return copy;
}
friend bool operator != (inverse_paire_iterateur const &s1,
inverse_paire_iterateur const &s2 ) {
return s1.m_tab != s2.m_tab || s1.m_pos != s2.m_pos;
}
};
std::map< T, U > m_map_1;
std::map< U, T > m_map_2;
public:
serializer_generique( std::pair< T, U > const in[size] ) :
m_map_1( in, in + size ),
m_map_2( inverse_paire_iterateur( in, 0 ),
inverse_paire_iterateur( in, size ) )
{
}
std::map< T, U > const & map() const { return m_map_1; }
std::map< U, T > const & map_inverse() const { return m_map_2; }
};

int main() {

typedef std::pair< std::string, int > elem;
elem const tableau[] = {
elem( "zéro", 0 ),
elem( "un", 1 ),
elem( "deux", 2 ),
elem( "trois", 3 ),
elem( "quatre", 4 )
};

serializer_generique< std::string, int, sizeof( tableau )/
sizeof( elem ) > serializer( tableau );
std::map< std::string, int > map1 = serializer.map();
std::map< int, std::string > map2 = serializer.map_inverse();

for ( std::map< std::string, int >::const_iterator it =
map1.begin();
it != map1.end();
++it
)
{
std::cout << it->first << " : " << it->second << "";
}
for ( std::map< int, std::string >::const_iterator it =
map2.begin();
it != map2.end();
++it
)
{
std::cout << it->first << " : " << it->second << "";
}

}
--
Affichage :
-
deux : 2
quatre : 4
trois : 3
un : 1
zéro : 0
0 : zéro
1 : un
2 : deux
3 : trois
4 : quatre
-

Merci beaucoup pour votre attention.
--
Alexis Guillaume
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Eric Pruneau
Le #6992201
"Alexis Guillaume" news:
Bonjour à tous.

Je pars d'un cas d'utilisation classique : on lit des valeurs
textuelles dans un fichier (std::string) et on les convertit en
entiers lors de l'éxécution du programme C++ (int, ou type enum).
L'opération inverse doit se faire bien sûr lors de l'écriture du
fichier.
Comme on aime les template en C++, supposons que T soit le type stocké
dans les fichiers et U le type stocké dans le programme utilisateur.

Un tel cas oblige bien à faire, à un moment ou à un autre, deux
fonctions de correspondance dans le programme C++ : l'une de T à U,
l'autre de U à T. On peut bien sûr les faire à base de if/else, mais
on préfère tout de même utiliser des tables de correspondances, par
exemple de type std::map pour une meilleure efficacité.

Déclarer en dur le contenu de std::map peut être assez pénible.
Surtout que dans notre cas il y en deux au contenu quasiment identique
pour un être humain mais très différent pour le compilateur puisque la
première est de type std::map<T, U> et la seconde std::map<U, T>.
J'ai donc écrit la classe template serializer_generique qui automatise
tout ce travail. Il suffit à l'utilisateur de déclarer un tableau
constant de std::pair< T, U > ; à partir d'un tel tableau, cette
classe va construire les deux std::map nécessaires pour faire les
conversions. On imagine bien sûr que les objets de cette classe ne
serviront que lors de l'initialisation du programme.

J'aimerais soumettre mon code aux membres de ce forum afin de récolter
des critiques qui me feront progresser. Oui je demande en quelque
sorte une revue de code gratuite ;-) mais il me semble que cela ne
déplaira pas à certains ici !
Je voudrais en fait savoir :
* En quoi mon code réinvente la roue (car je parierais bien que c'est
le cas) ;
* Si mon idée de départ est bonne, s'il y en a des meilleurs, etc...
* En supposant que cette idée soit bonne, quelle est la qualité de ce
code ?


hummm pour convertir un chiffre en string et vice versa, la méthode la
plus simple serait d'utiliser
ostringstream ou istringstream

ou même encore les reliques que sont atoi / itoa

int main()
{
string str = "1 2 3 4 5 67 89";
istringstream iss(str);
vector<int> MesValeurs;
while(!iss.eof())
{
int tmp;
iss >> tmp;
MesValeurs.push_back(tmp);
}
}
Publicité
Poster une réponse
Anonyme