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 :

[policy classes] changer l'opération par défaut à l'exécution


Sujet :

C++

  1. #1
    Membre averti Avatar de Ekinoks
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2003
    Messages
    687
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2003
    Messages : 687
    Points : 358
    Points
    358
    Par défaut [policy classes] changer l'opération par défaut à l'exécution
    Salut !

    Je m'intéresse au fonctionnement des classes de politique (policy classes), mais il y a une chose que je n'arrive pas à faire malgré mes nombreuses tentatives...
    Je viens donc vous demander conseille.

    Comme exemple, je prend celui qui est présent dans la FAQ (sans l'amélioration de la classe de trait pour que se soit plus lisible) :
    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
     
    template <typename T>
    struct Addition
    {
        static void Accumuler(T& Resultat, const T& Valeur)
        {
            Resultat += Valeur;
        }
    };
     
    template <typename T>
    struct Soustraction
    {
        static void Accumuler(T& Resultat, const T& Valeur)
        {
            Resultat -= Valeur;
        }
    };
     
     
    template <typename T, typename Operation = Addition<T> >
    struct Accumulation
    {
        static T Accumule(const T* Debut, const T* Fin)
        {
            T Resultat = 0;
            for ( ; Debut < Fin; ++Debut)
                Operation::Accumuler(Resultat, *Debut);
     
            return Resultat;
        }
    };
     
    template <typename T>
    T Accumule(const T* Debut, const T* Fin)
    {
        return Accumulation<T>::Accumule(Debut, Fin);
    }
     
    template <typename T, typename Operation>
    T Accumule(const T* Debut, const T* Fin)
    {
        return Accumulation<T, Operation>::Accumule(Debut, Fin);
    }
    Donc déjà, si j'ai bien compris, pour pouvoir utiliser "Accumule" il faut le faire de cette maniéré :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    int main()
    {
    	int i[3];
    	i[0] = 3;
    	i[1] = 4;
    	i[2] = 5;
     
    	printf("Addition = %d\n", Accumule(i, &i[3]));
    	printf("Soustraction = %d\n", Accumule<int, Soustraction<int> >(i, &i[3]));
    }

    On peu constater que pour effectuer l'opération par défaut, la syntaxe est beaucoup plus simple !
    Donc si dans notre programme on a une seul opération à effectuer, on a plutôt intéré à la mettre comme opération par défaut...
    Le problème est on que si on ne connais pas quel opération sera utiliser avent l'exécution, il faudrais avoir la possibilité de "changer" l'opération par défaut durant l'exécution du programme...

    Malheureusement je n'arrive pas à voir comment faire...

    Es qu'une tel chose est possible ?

    Merci pour votre aide.

  2. #2
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Les templates, c'est statique.
    Si tu veux pouvoir changer d'opération dynamiquement, tu dois instancier chaque template et rajouter du code pour utiliser les différentes instances.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Membre averti Avatar de Ekinoks
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2003
    Messages
    687
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2003
    Messages : 687
    Points : 358
    Points
    358
    Par défaut
    Merci Médinoc pour ta réponse

    Je suis pas sur d'avoir exactement tout compris ce que tu a dit, mais j'ai essayé de re réfléchir au problème en instanciant mes templates.

    J'ai un peu galèré, mais je suis arrivé à un résultat (qui a encore quelques petits soucies par contre )

    Voici ce que j'ai fait :
    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
    79
    80
    81
    82
     
    #include <iostream>
     
    /****************************************
    ******* Les Opperations possibles *******
    ****************************************/
    template <typename T>
    struct Opperation
    {
    	virtual void accumuler(T& Resultat, const T& Valeur) = 0;
    };
     
    template <typename T>
    struct Addition : Opperation<T>
    {
        void accumuler(T& Resultat, const T& Valeur)
        {
            Resultat += Valeur;
        }
    };
     
    template <typename T>
    struct Soustraction : Opperation<T>
    {
        void accumuler(T& Resultat, const T& Valeur)
        {
            Resultat -= Valeur;
        }
    };
     
    // En imaginant que d'autre Opperation viendrons se rajouter...
     
    /****************************************
    ****************************************/
     
    template <typename T>
    class MonOpperation
    {
    	Opperation<T> * opperation;
     
    	public :
    		MonOpperation(Opperation<T> * arg) : opperation(arg)
    		{ }
     
    		MonOpperation() : opperation(NULL)
    		{ }
     
    		void init(Opperation<T> * arg)
    		{
    			if(opperation!=NULL)
    				delete opperation;
    			opperation = arg;
    		}
     
    		Opperation<T> & operator () ()
    		{
    			return *opperation;
    		}
    };
     
    bool CHOIX_DE_L_OPPERATION()
    {
    	// choisir en fonction de...
    	return true;
    }
     
    int main()
    {
    	int a=0;
     
    	MonOpperation<int> monOpp;
     
    	if( CHOIX_DE_L_OPPERATION() )
    		monOpp.init( new Soustraction<int>() );
    	else
    		monOpp.init( new Addition<int>() );
     
    	for(int i=0; i<17; i++)
    		monOpp().accumuler(a, i);	// L'opération à effectué seras bien connue qu'a l'exécution
     
    	printf("a = %d\n", a);
    }
    J'ai donc réussi à ce que les opération effectué par "monOpp" peuvent changer d'une exécution à l'autre.

    Le nouveau problème qui viens se rajouter, c'est que comme il est impossible de déclarer virtual une méthode qui possède un template, je suis obliger de mettre le template sur la class "Opperation" entièrement.

    La conséquence est que le "type" des objets à accumuler doit étre défini lors de l'initialisation de "monOpp" et non pas lorsque de l'appelle à "accumuler" comme il serait souhaitable. :'(


    Donc, déjà, es que c'est de cette manière que tu voyais les choses Médinoc ? ou je suis partie dans une mauvaise direction ?
    Si non, comment pourrais-je faire pour palier à l'absence de la possibilité de mettre un template en virtual ?


    Merci.

  4. #4
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Oui, c'est à peu près ainsi que je voyais les choses.
    Par contre, je ne pense pas que tu puisses faire mieux et déterminer le type d'opérande dynamiquement.

    Sauf, là encore, en instanciant explicitement le truc pour chaque type possible, ce qui te donne deux dimensions pour les choix: http://medinoc.fr/web/Programmation/DvpCom_policy.htm

    Mais il te restera toujours le problème du passage d'argument...

    Dans ce genre de cas, à moins d'utiliser des VARIANT ou boost::variant, tu devrais peut-être rester au type d'opérande fixe.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #5
    Membre averti Avatar de Ekinoks
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2003
    Messages
    687
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2003
    Messages : 687
    Points : 358
    Points
    358
    Par défaut
    Merci pour ta réponse Médinoc.

    Tout d'abord j'aimerais faire une rectification,
    Dans le poste précédant j'ai dit :
    La conséquence est que le "type" des objets à accumuler doit étre défini lors de l'initialisation de "monOpp" et non pas lorsque de l'appelle à "accumuler" comme il serait souhaitable. :'(
    En fait, le fait que le type doit être connue lors de l'initialisation ne pose pas de problème.
    Le "vrai" problème est plutôt que le "Type" doit être connue à la déclaration de "monOpp" et donc à la compilation...
    Là, ça pose un réel problème, car d'une exécution à l'autre, les "types" sont obligatoirement les mêmes.

    Je pourrais effectivement utiliser des VARIANT, mais cela implique de connaitre la liste de toutes les opérandes possible à la compilation, ce qui peu être chose délicate :^/


    En réfléchissant je me suis dit qu'une solution serais d'utiliser des "void *"
    Comment ceci :
    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
    79
    80
    81
    82
    83
    #include <iostream>
     
    /****************************************
    ******* Les Opperations possibles *******
    ****************************************/
    struct Opperation
    {
    	virtual void accumuler(void* Resultat, const void* Valeur) = 0;
    };
     
    template <typename T>
    struct Addition : Opperation
    {
    	void accumuler(void* Resultat, const void* Valeur)
    	{
    		accumuler((T*)Resultat, (T*)Valeur);
    	}
     
     
    	void accumuler(T* Resultat, const T* Valeur)
    	{
    		*Resultat += *Valeur;
    	}
    };
     
    template <typename T>
    struct Soustraction : Opperation
    {
    	void accumuler(void* Resultat, const void* Valeur)
    	{
    		accumuler((T*)Resultat, (T*)Valeur);
    	}
     
    	void accumuler(T* Resultat, const T* Valeur)
    	{
    		*Resultat -= *Valeur;
    	}
    };
    /****************************************
    ****************************************/
     
    class MonOpperation
    {
    	Opperation * opperation;
     
    	public :
    		MonOpperation(Opperation * arg) : opperation(arg)
    		{ }
     
    		MonOpperation() : opperation(NULL)
    		{ }
     
    		void init(Opperation * arg)
    		{
    			if(opperation!=NULL)
    				delete opperation;
    			opperation = arg;
    		}
     
    		Opperation & operator () ()
    		{
    			return *opperation;
    		}
    };
     
    Opperation * CHOIX_DE_L_OPPERATION()
    {
    	return new Soustraction<int>();	// ou <float> ou ... en fonction de ...
    }
     
    int main()
    {
    	int a=0;
     
    	MonOpperation monOpp;
     
    	monOpp.init( CHOIX_DE_L_OPPERATION() );
     
    	for(int i=0; i<17; i++)
    		monOpp().accumuler(&a, &i); // en utilisant ici aussi des class trait pour envoyer le bon type (je ne l'ai pas fait ici pour que le code soit plus lisible)
     
    	printf("a = %d\n", a);
    }
    Cette fois-ci, les "types" peuvent effectivement changer d'une exécution à l'autre...

    Par contre je ne sais pas si l'utilisation de "void*" en C++ est très élégant... pense tu que cette solution est envisageable ?

    Merci.

  6. #6
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Si tu remplaces tes casts C-style par des static_cast<>, c'est assez élégant pour moi.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  7. #7
    Membre averti Avatar de Ekinoks
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2003
    Messages
    687
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2003
    Messages : 687
    Points : 358
    Points
    358
    Par défaut
    Ha oui c'est vrai quelque reste du C qui persiste :p

    Un grand merci pour ton aide Médinoc !!

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [SQLSERVER2000] Changer la collation par défaut d'une base
    Par vmolines dans le forum MS SQL Server
    Réponses: 1
    Dernier message: 13/12/2005, 15h22
  2. [unicode/ascii] Comment changer l'encodage par défaut????
    Par Mr Hyde dans le forum Général Python
    Réponses: 2
    Dernier message: 07/10/2005, 09h24
  3. Comment changer l'icone par défaut ?
    Par Mariussy dans le forum EDI
    Réponses: 3
    Dernier message: 19/09/2005, 20h23
  4. [Tomcat] Changer le répertoire par défaut
    Par leminipouce dans le forum Tomcat et TomEE
    Réponses: 3
    Dernier message: 23/05/2005, 16h06
  5. [2.1][Workspace]Changer le répertoire par défaut
    Par Pill_S dans le forum Eclipse Java
    Réponses: 4
    Dernier message: 29/06/2004, 13h34

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