IdentifiantMot de passe
Loading...
Mot de passe oubli� ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les r�ponses en temps r�el, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Ecriture g�n�rique pour manipuler des (w)string


Sujet :

C++

  1. #1
    Membre �clair�
    Inscrit en
    Avril 2005
    Messages
    1 110
    D�tails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par d�faut Ecriture g�n�rique pour manipuler des (w)string
    J'h�site entre deux �critures pour un m�me r�sultat:
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    template<typename C, typename Tr, typename Al>
    void all_trim(std::basic_string<C, Tr, Al> & s, C const *cs)
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    template<typename S>
    void all_trim(S & s, S::value_type const *cs)
    Jusqu'� pr�sent j'avais tendance � utiliser la premi�re �criture pour mes petites fonctions de manipulations de (w)string, mais je suis en train de revoir ma copie pour utiliser la deuxi�me. C'est plus court et plus simple finalement.
    Et �a me permet d'�crire ceci par exemple:
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    template<typename S>
    S trim(S && s, S::value_type const *cs)
    {
    	S ms(std::forward<S>(s));
    	all_trim(ms, cs);
    	return ms;
    }
    Des avis ?
    Merci.

  2. #2
    R�dacteur/Mod�rateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 153
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 38
    Localisation : Canada

    Informations professionnelles :
    Activit� : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 153
    Billets dans le blog
    4
    Par d�faut
    Si tu ne comptes utiliser que des std::(w)string, autant aller au plus simple � �crire et comprendre imo.
    Pensez � consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation r�seau ?
    Aucune aide via MP ne sera dispens�e. Merci d'utiliser les forums pr�vus � cet effet.

  3. #3
    Membre �clair�
    Inscrit en
    Avril 2005
    Messages
    1 110
    D�tails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par d�faut
    Je croyais tout bon, et puis patatras, ceci ne compile pas:
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    template<typename S>
    S trim(S && s, S::value_type const *cs)
    {
    	S ms(std::forward<S>(s));
    	all_trim(ms, cs);
    	return ms;
    }
    Visual Studio 2015 me donne ces erreurs:
    error C2672: 'trim': no matching overloaded function found_
    error C2893: Failed to specialize function template 'S trim(S &&,const S::value_type *)'_

    Je dois faire comme ceci
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    template<typename S, typename C>
    S trim(S && s, C const *cs)
    {
    	S ms(std::forward<S>(s));
    	all_trim(ms, cs);
    	return ms;
    }
    Mais je ne comprends pas trop pourquoi... (bien que �a ne me d�range pas, mais comprendre c'est toujours bon )

  4. #4
    Expert �minent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activit� : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par d�faut
    Salut,

    Comme tu utilises std::wstring et std::string, tu fournis en r�alit� une sp�cialisation de std::basic_string. Si bien que S::value_type n'est en r�alit� que le typedef que l'on trouve dans std::basic_string qui correspond au type de caract�res � utiliser.

    Or, ce typedef est d�pendant de la sp�cialisation de std::basic_string que tu utilise (et qui te sert de param�tre template), tu devrais donc -- si je ne m'abuse -- clairement sp�cifier qu'il est d�p�ndant du param�tre template, sous une forme (non test�e) qui serait proche de
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    template<typename S>
    S trim(S && s, typename S::value_type const *cs)
    {
    	S ms(std::forward<S>(s));
    	all_trim(ms, cs);
    	return ms;
    }
    (d'ailleurs il y a peut-etre bien un typedef plus int�ressant � utiliser comme const_pointer)

    Une autre solution pourrait �tre (histoire de t'assurer que C fait bien partie de la sp�cialisation de std::basic_string repr�sent�e par S) de fournir une valeur par d�faut pour C, sous la forme de (toujours non test�)
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    template<typename S, typename C= typename S::value_type> //  je préférerais vraiment const_pointer à value_type
    S trim(S && s, C const *cs)
    {
    	S ms(std::forward<S>(s));
    	all_trim(ms, cs);
    	return ms;
    }
    A m�diter: La solution la plus simple est toujours la moins compliqu�e
    Ce qui se con�oit bien s'�nonce clairement, et les mots pour le dire vous viennent ais�ment. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 f�vrier 2014
    mon tout nouveau blog

  5. #5
    R�dacteur/Mod�rateur
    Avatar de JolyLoic
    Homme Profil pro
    D�veloppeur informatique
    Inscrit en
    Ao�t 2004
    Messages
    5 463
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 51
    Localisation : France, Yvelines (�le de France)

    Informations professionnelles :
    Activit� : D�veloppeur informatique
    Secteur : High Tech - �diteur de logiciels

    Informations forums :
    Inscription : Ao�t 2004
    Messages : 5 463
    Par d�faut
    Je pr�f�re ta seconde �criture, en plus d'�tre plus simple, elle fonctionnera avec plus de types semblables � des strings que std::basic_string. La premi�re n'a d'int�r�t � mon sens que si tu veux jouer avec les param�tres, par exemple convertir ta std::basic_string<C, Tr, Al> en std::basic_string<C, AnotherCharTrait, Al>.
    Ma session aux Microsoft TechDays 2013 : D�velopper en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage � la d�couverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'h�sitez pas � me contacter.

  6. #6
    Membre �clair�
    Inscrit en
    Avril 2005
    Messages
    1 110
    D�tails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par d�faut
    Merci pour vos r�ponses !
    J'y vois un peu plus clair

    Apr�s d'autres petits tests, la pr�sence ou non du mot cl� typename ne change rien, la m�me erreur de compilation survient.
    C'est la pr�sence de l'op�rateur && qui semble perturber le compilateur.

    Je reprends ici le code (adapt� � juste titre comme propos� par koala01)
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    template<typename S>
    inline S trim(S && s, typename S::const_pointer cs)
    {
    	S ms(std::forward<S>(s));
    	all_trim(ms, cs);
    	return ms;
    }
    Ce code n'est accept� que si le param�tre "s" est une rvalue.

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    template<typename S, typename Cptr = typename S::const_pointer>
    inline S trim(S && s, Cptr cs)
    {
    	S ms(std::forward<S>(s));
    	all_trim(ms, cs);
    	return ms;
    }
    Celui-ci semble toujours �tre accept�, lvalue ou rvalue pour le param�tre "s".

    Moi qui croyais avoir tout compris, voici une petite zone d'ombre (pas bien grave ).

  7. #7
    Invit�
    Invit�(e)
    Par d�faut
    Bonjour,

    Citation Envoy� par camboui Voir le message
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    template<typename S, typename Cptr = typename S::const_pointer>
    inline S trim(S && s, Cptr cs)
    {
    	S ms(std::forward<S>(s));
    	all_trim(ms, cs);
    	return ms;
    }
    Celui-ci semble toujours �tre accept�, lvalue ou rvalue pour le param�tre "s".
    Il est toujours accept� car le param�tre template Cptr est d�duit � partir du type du param�tre que tu rentres et non du type par d�faut que tu lui donnes, retirer = typename S::const_pointer n'y changerait rien.

    Tu as trouv� le pourquoi dans le lien que tu donnes : lorsque tu passes une lvalue, S comporte �galement la r�f�rence. Et pour aller plus loin, rends-toi compte que S ms ainsi que le retour de ta fonction trim() sont de fait �galement des r�f�rences de ton entr�e, qui se voit ainsi modifi�e. Je ne suis pas certain que ce soit r�ellement ce que tu souhaites.

    Dans tous les cas std::remove_reference � la rescousse

  8. #8
    Membre �clair�
    Inscrit en
    Avril 2005
    Messages
    1 110
    D�tails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par d�faut
    Oufti
    Mon dieu, la grosse bourde
    Heureusement que tu passais par ici, toi

    Voici donc le "bon" code
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    template<typename S>
    inline std::remove_reference_t<S>
    	trim(S && s, typename std::remove_reference_t<S>::const_pointer cs)
    {
    	std::remove_reference_t<S> ms(std::forward<S>(s));
    	all_trim(ms, cs);
    	return ms;
    }
    Test� et... je vous laisse le soin d'approuver.

  9. #9
    Invit�
    Invit�(e)
    Par d�faut
    Aurais-je oubli� de mentionner que les cv-qualifiers �taient �galement conserv�s ?
    Ex. : que se passe-t-il si tu passes std::string const str en param�tre ?

    Petit tableau r�capitulatif :

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    int x = 22;
    int & rx = x;
    int const cx = x;
    int const & rcx = x;
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    template <typename T>
    void f(T && param);
    f(x); Tint &.
    param est de type int &
    f(rx); Tint &.
    param est de type int &
    f(cx); Tint const &.
    param est de type int const &
    f(rcx); Tint const &.
    param est de type int const &
    f(22); Tint.
    param est de type int &&
    Derni�re modification par Invit� ; 16/10/2016 � 19h29.

  10. #10
    R�dacteur/Mod�rateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 153
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 38
    Localisation : Canada

    Informations professionnelles :
    Activit� : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 153
    Billets dans le blog
    4
    Par d�faut
    Pourquoi utiliser && ici ?
    je ne comprends pas l'utilit�, si on doit utiliser remove reference et travailler sur une copie, pourquoi ne pas simplement passer un const& ou une copie directement ?
    Pensez � consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation r�seau ?
    Aucune aide via MP ne sera dispens�e. Merci d'utiliser les forums pr�vus � cet effet.

  11. #11
    Membre �clair�
    Inscrit en
    Avril 2005
    Messages
    1 110
    D�tails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par d�faut
    On travaille sur une copie si le param�tre est une lvalue.
    Si le param�tre est une rvalue, on travaille sur celle-ci directement. C'est d'ailleurs pour �a que j'ai mis le std::forward (sans lui le passage du param�tre via && ne sert effectivement plus � rien).

  12. #12
    Membre Expert
    Homme Profil pro
    Ing�nieur d�veloppement logiciels
    Inscrit en
    Juin 2011
    Messages
    760
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, H�rault (Languedoc Roussillon)

    Informations professionnelles :
    Activit� : Ing�nieur d�veloppement logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 760
    Par d�faut
    En cr�ant ms, tu travaille toujours sur une copie.

  13. #13
    Membre �clair�
    Inscrit en
    Avril 2005
    Messages
    1 110
    D�tails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par d�faut
    Non.

    Voici un code pour le prouver (la fonction template test_moved_param(S && s, char const *val) est semblable � la fonction template trim(S && s, typename std::remove_reference_t<S>::const_pointer cs) pr�c�dante).
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    class full_object
    {
    	std::string last_call;
    	std::string m_value;
    public:
    	full_object() : last_call("Default constructor"),
    		m_value()
    		{ display(); }
    	full_object(const full_object & fo) : last_call("Copy constructor"),
    		m_value(fo.m_value)
    		{ display(); }
    	full_object(full_object && fo) : last_call("Move constructor"),
    		m_value(std::move(fo.m_value))
    		{ display(); }
    	full_object & operator=(const full_object & fo)
    	{
    		last_call = "Copy assignment operator";
    		m_value = fo.m_value;
    		display();
    		return *this;
    	}
    	full_object & operator=(full_object && fo)
    	{
    		last_call = "Move assignment operator";
    		m_value = std::move(fo.m_value);
    		display();
    		return *this;
    	}
    	virtual ~full_object()
    	{
    		last_call = "Destructor";
    		display();
    	}
     
    	full_object & assign(char const *val)
    		{ m_value = val; return *this; }
    	full_object & append(char const *val)
    		{ m_value += val; return *this; }
    	full_object & assign(const full_object & fo)
    		{ m_value = fo.m_value; return *this; }
    	full_object & append(const full_object & fo)
    		{ m_value += fo.m_value; return *this; }
    	void display()
    		{ std::cout << get() << std::endl; }
    	std::string get()
    		{ return last_call + " - value=" + m_value; }
    };
     
    full_object operator+(const full_object & lfo, const full_object & rfo)
    {
    	full_object tfo;
    	tfo.assign(lfo);
    	tfo.append(rfo);
    	return tfo;
    }
     
    template<typename S>
    inline std::remove_reference_t<S>
    	test_moved_param(S && s, char const *val)
    {
    	std::remove_reference_t<S> ms(std::forward<S>(s));
    	ms.assign(val);
    	return ms;
    }
     
    int main()
    {
    	full_object fo1;
    	std::cout << ".\t" << fo1.get() << std::endl;
    	fo1.assign("fo1");
    	std::cout << ".\t" << fo1.get() << std::endl;
    	full_object fo2 = test_moved_param(fo1, "fo1, lvalue");
    	std::cout << ".\t" << fo2.get() << std::endl;
    	full_object fo3 = test_moved_param(fo1.append("/").append(fo2), "fo1.append(\"/\").append(f02), lvalue");
    	std::cout << ".\t" << fo3.get() << std::endl;
    	full_object fo4 = test_moved_param(fo2.append("|") + fo3, "fo2+fo3, rvalue");
    	std::cout << ".\t" << fo4.get() << std::endl;
    }
    Et voici l'output:
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    Default constructor - value=
    .       Default constructor - value=
    .       Default constructor - value=fo1
    Copy constructor - value=fo1
    Move constructor - value=fo1, lvalue
    Destructor - value=
    .       Move constructor - value=fo1, lvalue
    Copy constructor - value=fo1/fo1, lvalue
    Move constructor - value=fo1.append("/").append(f02), lvalue
    Destructor - value=
    .       Move constructor - value=fo1.append("/").append(f02), lvalue
    Default constructor - value=
    Move constructor - value=fo1, lvalue|fo1.append("/").append(f02), lvalue
    Destructor - value=
    Move constructor - value=fo1, lvalue|fo1.append("/").append(f02), lvalue
    Move constructor - value=fo2+fo3, rvalue
    Destructor - value=
    Destructor - value=
    .       Move constructor - value=fo2+fo3, rvalue
    Destructor - value=fo2+fo3, rvalue
    Destructor - value=fo1.append("/").append(f02), lvalue
    Destructor - value=fo1, lvalue|
    Destructor - value=fo1/fo1, lvalue
    En gras et en couleur l'affichage lorsque le code std::remove_reference_t<S> ms(std::forward<S>(s)); est execut�.
    En vert on s'attend � une lvalue et c'est bien le Copy Construtor qui est appel�.
    En rouge on s'attend � une rvalue et c'est bien le Move Construtor qui est appel�.
    On voit donc bien que les rvalue ne sont pas copi�es et restent des rvalue.

  14. #14
    Membre Expert
    Homme Profil pro
    Ing�nieur d�veloppement logiciels
    Inscrit en
    Juin 2011
    Messages
    760
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, H�rault (Languedoc Roussillon)

    Informations professionnelles :
    Activit� : Ing�nieur d�veloppement logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 760
    Par d�faut
    Ici, il faut prendre le "une copie", comme "une autre instance". Ton message pr�c�dent sous-entend que si le param�tre est une rvalue, le param�tre est utilis� directement, or non, il y a cr�ation d'une nouvelle instance, d'o� le "une copie" qui est ici ambigu.

    Ce que dit @Bousk et que si tu utilises toujours une nouvelle instance, autant prendre un type plein en param�tre (= un type sans r�f�rence). Ainsi, il n'y a plus besoin de cr�er une nouvelle instance et tu simplifies le code.
    Et tu profites �galement de la copie �lision, ce qui veut dire que pour auto s = trim("abc"s); et avec la RVO (une sorte de copie �lision pour le retour de fonction), il y un constructeur avec une cha�ne, 0 constructeur de copie, 0 constructeur de d�placement, contrairement � la version avec std::forward qui utilise un constructeur de d�placement.

  15. #15
    R�dacteur/Mod�rateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 153
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 38
    Localisation : Canada

    Informations professionnelles :
    Activit� : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 153
    Billets dans le blog
    4
    Par d�faut
    Merci jo, je pensais devenir fou.
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    trim(S && s, typename std::remove_reference_t<S>::const_pointer cs)
    {
    	std::remove_reference_t<S> ms(std::forward<S>(s));
    est exactement similaire �
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    trim(S ms, typename S::const_pointer cs)
    {
    si ma sant� mentale n'est pas encore d�faillante.

    edit: bien vu, je l'avais loup�
    Pensez � consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation r�seau ?
    Aucune aide via MP ne sera dispens�e. Merci d'utiliser les forums pr�vus � cet effet.

  16. #16
    Membre Expert
    Homme Profil pro
    Ing�nieur d�veloppement logiciels
    Inscrit en
    Juin 2011
    Messages
    760
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, H�rault (Languedoc Roussillon)

    Informations professionnelles :
    Activit� : Ing�nieur d�veloppement logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 760
    Par d�faut
    On peut m�me �jecter std::remove_reference.

  17. #17
    Membre �clair�
    Inscrit en
    Avril 2005
    Messages
    1 110
    D�tails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par d�faut
    Vous avez raison.
    A force de vouloir caser ce foutu && j'en oublie de faire simple pour faire compliqu�.
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    template<typename S>
    inline S test_moved_param(S ms, char const *val)
    {
    	ms.assign(val);
    	return ms;
    }
    R�sultat:
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    Default constructor - value=
    .       Default constructor - value=
    .       Default constructor - value=fo1
    Copy constructor - value=fo1
    Move constructor - value=fo1, lvalue
    Destructor - value=
    .       Move constructor - value=fo1, lvalue
    Copy constructor - value=fo1/fo1, lvalue
    Move constructor - value=fo1.append("/").append(f02), lvalue
    Destructor - value=
    .       Move constructor - value=fo1.append("/").append(f02), lvalue
    Default constructor - value=
    Move constructor - value=fo1, lvalue|fo1.append("/").append(f02), lvalue
    Destructor - value=
    Move constructor - value=fo2+fo3, rvalue
    Destructor - value=
    .       Move constructor - value=fo2+fo3, rvalue
    Destructor - value=fo2+fo3, rvalue
    Destructor - value=fo1.append("/").append(f02), lvalue
    Destructor - value=fo1, lvalue|
    Destructor - value=fo1/fo1, lvalue
    Je vais un faire un peu de "C" avec de z'olis pointeurs pour me changer les id�es

+ R�pondre � la discussion
Cette discussion est r�solue.

Discussions similaires

  1. Bibliotheque pour manipuler des buffer string
    Par Tail dans le forum Biblioth�que standard
    R�ponses: 1
    Dernier message: 09/08/2009, 20h57
  2. Meilleure methode pour manipuler des images
    Par etranger dans le forum Modules
    R�ponses: 2
    Dernier message: 16/02/2007, 13h06
  3. API pour manipuler des RPM
    Par pcery dans le forum API standards et tierces
    R�ponses: 1
    Dernier message: 07/08/2006, 14h44
  4. Quel langage pour manipuler des entiers très longs ?
    Par mis_dj dans le forum Langages de programmation
    R�ponses: 8
    Dernier message: 10/05/2006, 21h12
  5. Delphi 2005 pour manipuler des formulaires MS-Access ??
    Par Mustard007 dans le forum Bases de donn�es
    R�ponses: 4
    Dernier message: 18/10/2005, 21h39

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo