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 :

expression template et constructeur par défaut


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Par défaut expression template et constructeur par défaut
    Bonjour à tous.

    Je suis en train de m'amuser à construire quelques expressions templates en me basant sur l'article http://www.angelikalanger.com/Articl...nTemplates.htm

    avec quelques ajouts de C++11.
    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
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
     
    #include <iostream> 
     
    template <typename T> 
    class Expression 
    { 
        const T& expr; 
    public: 
        Expression(const T& t2):expr(t2){} 
        typename T::result operator()() 
        { 
            std::cout<<"expr eval"<<std::endl;     
            expr(); 
        } 
    }; 
     
    template <class T> Expression<T> makeExpression(const T& t) 
    { 
        std::cout<<"make expr"<<std::endl; 
        return Expression<T>(t); 
    } 
     
    template <class T> class Var 
    { 
        T t; 
    public : 
        Var(const Var& o):t(o.t){std::cout<<"copy"<<std::endl;} 
        Var(T t2):t(t2){std::cout<<"value "<<t<<std::endl;} 
        Var():t(T()){} 
        Var(Var&& o):t(std::move(o.t)){std::cout<<"move"<<std::endl;} 
        T operator()() const 
        { 
            return t; 
        } 
     
        Var& operator=(T o) 
        { 
            t=o; 
            return *this; 
        } 
        ~Var(){std::cout<<"dst"<<std::endl;} 
        typedef T result; 
    }; 
     
    template <typename T,typename U,typename Op> class ExpressionBin 
    { 
        const T& t; 
        const U& u; 
        Op op; 
    public: 
        ExpressionBin(){std::cout<<"wtf"<<std::endl;} // <<LA 
     
        ExpressionBin(const T& tt,const U& uu): 
        t(tt), 
        u(uu),op(Op()) 
        { 
     
        } 
     
        typedef decltype(op(T(),U())) result; 
        result operator()() const 
        { 
            return op(t,u); 
        } 
    }; 
     
    #define helperEval(op)     template <class T, class U>  \ 
        decltype((typename T::result() op  typename U::result())) \ 
        operator()(const T& t,const U& u) const \ 
        { \ 
            std::cout<<#op " called " \ 
            <<t()<<" "<<u()<<std::endl;    \ 
            return t() op u(); \ 
        } 
     
    struct plus 
    { 
        helperEval(+) 
    }; 
     
    struct mul 
    { 
         helperEval(*) 
    }; 
     
    struct DIV 
    { 
         helperEval(/) 
    }; 
     
    struct moins 
    { 
         helperEval(-) 
    }; 
     
     
    template <class T, class U> ExpressionBin<T,U,plus> 
     operator+(const T& t,const U& u) 
    { 
        return ExpressionBin<T,U,plus>(t,u); 
    } 
    template <class T, class U> ExpressionBin<T,U,mul> 
    operator*(const T& t,const U& u) 
    { 
        return ExpressionBin<T,U,mul>(t,u); 
    } 
     
    template <class T, class U> ExpressionBin<T,U,DIV> 
    operator/(const T& t,const U& u) 
    { 
        return ExpressionBin<T,U,DIV>(t,u); 
    } 
     
    template <class T, class U> ExpressionBin<T,U,moins> 
    operator-(const T& t,const U& u) 
    { 
        return ExpressionBin<T,U,moins>(t,u); 
    } 
     
    int main(int argc, char *argv[]) 
    { 
        Var<int> x(5); 
        const Var<int> y(3); 
        const Var<double> z(+2.5); 
        Var<double> a; 
        Var<int> b=2; 
        auto e= makeExpression(x*y+z); 
        std::cout<<"========="<<std::endl; 
        a=0.5; 
        std::cout<<"=>"<<e()<<std::endl; 
        std::cout<<"========="<<std::endl; 
        return 0; 
    }
    Pour le moment le code marche (disons qu'il me donne le résultat attendu) mais j'ai une incompréhension

    Si je commente le constructeur par défaut de ExpressionBin, le code ne veut plus compiler car il ne trouve pas le dit constructeur. Jusque là c'est logique ....

    Sauf que ce soucis apparaît seulement quand j'ai plus d'une opération dans mon calcul. si je fais seulement x*y, pas besoin constructeur par défaut. Mais dès que je passe à x*y+z (ou quoi que ce soit d'autre), j'en ai besoin.

    Ce qui me choque, c'est que le constructeur n'est jamais appelé et que les références puissent être laissées non initialisées !! D'ailleurs, si je le remplace par ExpressionBin()=default;
    ca plante !!

    Est ce que quelqu'un aurait une explication à ce phénomène ?

    Merci beaucoup !
    David.
    "Never use brute force in fighting an exponential." (Andrei Alexandrescu)

    Mes articles dont Conseils divers sur le C++
    Une très bonne doc sur le C++ (en) Why linux is better (fr)

  2. #2
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Ça ne viendrait pas du fait que le type de z est différent de celui de x et y ?

    Je ne comprend d'ailleurs pas comment peut s'effectuer l'opération x*y. Je ne vois pas d'opérateur * pour la classe Var. L'opérateur () doit être automatiquement appelé, mais je ne connais pas ce mécanisme.

  3. #3
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Je n'ai pas de problème pour compiler ton code avec g++ 4.7.3.
    Si toutefois je corrige la ligne 12...

  4. #4
    Membre Expert

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Par défaut
    Je n'ai pas tout les éléments de réponse à tes questions. Par contre, en utilisant des std::declval à la place d'utiliser explicitement les constructeurs dans tes typedef (c'est là que tu utilises tes constructeurs par défaut, ce n'est pas une utilisation runtime, mais ça implique que la syntaxe soit valide), ça devrait corriger certains comportements je pense.

  5. #5
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Par défaut
    oodini >> Oui, le code compile et donne le résultat attendu. Sinon j'ai des opérateurs templates pour +, *, / et - (l97 a 110)

    Flob90 >> merci, je n'avais pas vu std::declval. Je suis pas encore totalement au point sur C++11. Et effectivement, ca corrige le comportement.

    Reste plus qu'un bug au niveau logique de l'application. Si je trace mes appels, j'ai
    * called 5 3
    + called 15 2.5
    * called 5 3
    =>17.5
    Le deux premières lignes sont normales mais je en vois pas pourquoi la dernière apparaît ... D'autant plus que le type de e est bon
    Expression< ExpressionBin< ExpressionBin<Var<int>, Var<int>, mul>, Var<double>,plus> >
    "Never use brute force in fighting an exponential." (Andrei Alexandrescu)

    Mes articles dont Conseils divers sur le C++
    Une très bonne doc sur le C++ (en) Why linux is better (fr)

  6. #6
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Citation Envoyé par Davidbrcz Voir le message
    oodini >> Oui, le code compile et donne le résultat attendu. Sinon j'ai des opérateurs templates pour +, *, / et - (l97 a 110
    Sur les ExpressionBin, mais pas sur les var.
    Or, quand tu fais x*y, il s'agit de Var.

    Si quelqu'un veut bien m'expliquer la chose...

  7. #7
    Membre Expert

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Par défaut
    @oodini: Les opérateurs de David matchent bien x*y avec T=var<int> et U=var<int>.

    @David: Le fait que le comportement soit différent entre =default et fait à la main doit venir d'un détail de la norme, je regardes plus en détail.

    Pour le std::declval, en réalité c'est la même idée qu'avant le C++11, on se débrouille pour avoir des fonctions qui donne le type qu'on veut sans avoir à réellement les appeler. decltype simplifie la syntaxe mais ne change pas la façon de faire.

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

Discussions similaires

  1. comment modifier le constructeur par défaut
    Par une_tite_question dans le forum NetBeans
    Réponses: 6
    Dernier message: 18/06/2008, 21h24
  2. notion de constructeur par défaut
    Par new_wave dans le forum Débuter avec Java
    Réponses: 2
    Dernier message: 09/05/2008, 19h33
  3. Réponses: 8
    Dernier message: 27/10/2006, 14h36
  4. Réponses: 11
    Dernier message: 25/08/2006, 16h00
  5. Constructeur par défaut en cas de surcharge
    Par gigi_m dans le forum MFC
    Réponses: 4
    Dernier message: 08/06/2005, 09h58

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