Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Que pensez-vous de ce code de serialization ?

1 réponse
Avatar
Alexis Guillaume
Bonjour =E0 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'=E9x=E9cution du programme C++ (int, ou type enum).
L'op=E9ration inverse doit se faire bien s=FBr lors de l'=E9criture du
fichier.
Comme on aime les template en C++, supposons que T soit le type stock=E9
dans les fichiers et U le type stock=E9 dans le programme utilisateur.

Un tel cas oblige bien =E0 faire, =E0 un moment ou =E0 un autre, deux
fonctions de correspondance dans le programme C++ : l'une de T =E0 U,
l'autre de U =E0 T. On peut bien s=FBr les faire =E0 base de if/else, mais
on pr=E9f=E8re tout de m=EAme utiliser des tables de correspondances, par
exemple de type std::map pour une meilleure efficacit=E9.

D=E9clarer en dur le contenu de std::map peut =EAtre assez p=E9nible.
Surtout que dans notre cas il y en deux au contenu quasiment identique
pour un =EAtre humain mais tr=E8s diff=E9rent pour le compilateur puisque la=

premi=E8re est de type std::map<T, U> et la seconde std::map<U, T>.
J'ai donc =E9crit la classe template serializer_generique qui automatise
tout ce travail. Il suffit =E0 l'utilisateur de d=E9clarer un tableau
constant de std::pair< T, U > ; =E0 partir d'un tel tableau, cette
classe va construire les deux std::map n=E9cessaires pour faire les
conversions. On imagine bien s=FBr 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=E9colter
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=E9plaira pas =E0 certains ici !
Je voudrais en fait savoir :
* En quoi mon code r=E9invente la roue (car je parierais bien que c'est
le cas) ;
* Si mon id=E9e de d=E9part est bonne, s'il y en a des meilleurs, etc...
* En supposant que cette id=E9e soit bonne, quelle est la qualit=E9 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
=3D 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 !=3D (inverse_paire_iterateur const &s1,
inverse_paire_iterateur const &s2 ) {
return s1.m_tab !=3D s2.m_tab || s1.m_pos !=3D 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[] =3D {
elem( "z=E9ro", 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 =3D serializer.map();
std::map< int, std::string > map2 =3D serializer.map_inverse();

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

}
--------------------
Affichage :
-------------------
deux : 2
quatre : 4
trois : 3
un : 1
z=E9ro : 0
0 : z=E9ro
1 : un
2 : deux
3 : trois
4 : quatre
-------------------

Merci beaucoup pour votre attention.
--
Alexis Guillaume

1 réponse

Avatar
Eric Pruneau
"Alexis Guillaume" a écrit dans le message de
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);
}
}