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

Langage C++ Discussion :

Le compilateur ne renvoie pas de lvalue error pour des complexes


Sujet :

Langage C++

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    4
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 4
    Par défaut Le compilateur ne renvoie pas de lvalue error pour des complexes
    Bonjour,
    j'ai un probleme bete, c'est que les compilateurs que j'ai (icc, g++) ne disent rien lorsqu'une valeur complexe est utilisee comme lvalue. Alors qu'il genere bien une erreur pour les doubles, il ne dit rien pour les complexes. Y-a t'il une option de compilation qui permettrait au compilateur de signaler cette erreur ?
    Voici l'exemple qui compile (alors qu'il ne devrait pas) :



    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
    #include <complex>
    #include <iostream>
    #include <vector>
     
    using namespace std;
     
    template<class T>
    class Vector
    {
    protected :
      vector<T> data_;
     
    public :
     
      Vector(int n) : data_(n)
      {
      }
     
      T operator()(int i) const
      {
        return data_[i];
      }
     
    };
     
     
    int main()
    {
      int n = 10;
      //Vector<double> x(n);                                                                                                                                                                        
      //x(0) = 1.3;                                                                                                                                                                                 
     
      Vector<complex<double> > x(n);
      x(0) = complex<double>(1.3, 4.5);
     
      return 0;
    }
    Si vous decommentez les lignes pour double (et commentez celles avec complex<double> ), vous verrez que ca genere bien l'erreur souhaitee a la compilation.

    Je precise que je veux implementer un operateur () const qui renvoie une valeur et pas une reference, et je voudrais que le compilo signale les endroits ou ya x(i) = quelque chose.

  2. #2
    Membre éclairé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    47
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 47
    Par défaut
    Si tu ajoutes un const, tu auras bien ton erreur (mais elle ne sera pas aussi évidente à comprendre qu'avec un type de base):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    const T operator()(int i) const

  3. #3
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Septembre 2006
    Messages : 37
    Par défaut
    Citation Envoyé par marcolo Voir le message
    Voici l'exemple qui compile (alors qu'il ne devrait pas)
    Il doit compiler, et il compile.

    Mais ton problème n'a rien à voir avec std::complex<>. Teste :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
     
    struct S {} s;
     
    int main { 
     
      Vector< S > x(10);
     
      x(0)= s;
    }
    Tu observes une différence entre un double et un std::complex< double > parce que l'un est un class type et pas l'autre. Quand tu écris
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      x(0)= complex< double >(1.3, 4.5);
    le compilateur lit
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    x(0).operator=(complexe< double >(1.3, 4.5))
    ce qui est valide. À l'exécution c'est une no-op ; as-tu regardé la valeur de x(0) après l'affectation ?

    Je precise que je veux implementer un operateur() const qui renvoie une valeur et pas une reference, et je voudrais que le compilo signale les endroits ou ya x(i) = quelque chose.
    Ce n'est pas possible, sauf à suivre le conseil de alexisdm.

    Pourquoi tiens-tu à ce que ton operator() const retourne une valeur ?

  4. #4
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    4
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 4
    Par défaut
    Merci pour vos explications, j'ai bien compris le probleme. J'ai adopte la solution de alexisdm en rajoutant un const. C'est vrai que l'erreur obtenue est moins explicite, mais ce que je voulais avant tout c'etait la generation d'une erreur.

  5. #5
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Salut,
    La constance suffit à générer une erreur que le retour se fasse par référence ou par valeur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      T const &operator()(int i) const
    ou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      T const operator()(int i) const

  6. #6
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Septembre 2006
    Messages : 37
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    La constance suffit à générer une erreur que le retour se fasse par référence ou par valeur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      T const operator()(int i) const
    Mais, dans ce cas, n'interdit-elle pas la RVO ?

  7. #7
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Citation Envoyé par N i h i l Voir le message
    Mais, dans ce cas, n'interdit-elle pas la RVO ?
    Quel est le rapport avec la question initiale ?

  8. #8
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Septembre 2006
    Messages : 37
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Quel est le rapport avec la question initiale ?
    Dans la question initiale, marcopolo insistait pour un retour par valeur. Un retour par référence constante aurait répondu à la question.

    Un retour par valeur constante réponds aussi à la question ; mais à quel coût ? En particulier, la RVO est-elle toujours possible ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Vector< Type > v;
    // ...
    Type x(v(i)); // 1
    Le compilateur est-il autorisé à faire l'élision de la copie en 1 ?

  9. #9
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    C'est un vecteur qui retourne une copie ou une référence d'un de ses membres. Je ne vois pas où la (n)rvo peut s'appliquer.

  10. #10
    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
    @OP: Pour ce que tu veux, comme ca a été dit ca revient à ca :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    struct A {};
     
    struct B
    {
      A a;
      A operator()() const { return a; }
    };
     
    B b;
    b() = A();
    Pour bien comprendre il faut savoir que ce qui est retourné par ta fonction est qualifié de r-value (pr-value pour être exact, historiquement c'est les valeurs qui sont à droite du signe d'affectation, =). Or le signe d'affectation est traité différement selon que l'objet est un objet de classe (dans le sens le plus général) ou non. Si ce n'est pas le cas ca provoque une erreur. Sinon le compilateur a le droit d'appeler les fonctions membre d'une r-value, ici l'opérateur d'affectation.

    Les solutions proposées fonctionnent car dans ton cas (et c'est vraie en général) l'opérateur d'affectation n'est pas une fonction qualifié const (*), et ne peut donc être utilisé sur une valeur non qualifié de const (que ce soit un r-value const T, ou un l-value const T&)

    NB: Et si tu optes pour cette solution, je pense qu'utiliser un retour par référence et non copie sera plus profitable. La constance indique que ton objet ne peut pas être modifié (**), ce qui est ce que tu veux, et tu gagnes une copie.

    (*) On pourrait en imaginer un const, cependant lui trouver un sens n'est surment pas évident, comment peut-on assigner une valeur sans changer celle-ci ? (C'est plus un problème sémantique que technique)

    (**) A nouveau c'est une interdiction sémantique, on peut toujours la forcer mais c'est au péril de l'utilisateur.

    @N i h i l : Il n'y a pas de RVO dans ce code, le RVO sert à éviter de créer un objet (non volatile, non static) dans le corps de la fonction puis de le copier dans le retour de la fonction. Ici l'object existe avant, il y a soit un retour par référence soit une copie, je ne vois pas quelle copie tu voudrais enlever.

    Pour la copie elision, si tu prends la version qui retourne une copie (constante) et une fonction qui attend une copie (même type au cv près), alors elle pourra avoir lieux.

  11. #11
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Par défaut
    Citation Envoyé par N i h i l Voir le message
    Pourquoi tiens-tu à ce que ton operator() const retourne une valeur ?
    En environnement multithreadé, c'est quasiment indispensable.

  12. #12
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Citation Envoyé par Matthieu Brucher Voir le message
    En environnement multithreadé, c'est quasiment indispensable.
    Pourquoi ?

  13. #13
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Par défaut
    Si tu renvoies une référence et que tu travailles dessus, tu n'es pas certain qu'elle reste valide, sauf à garder un gros mutex. Et c'est pas très performant dans ce cas.

  14. #14
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Mais si tu dois copier tout les éléments de ton vecteur, ça peut aussi être assez inefficace, non ?

  15. #15
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Par défaut
    Tout à fait. Dans ce cas, il vaut peut-être mieux travailler avec des pointeurs intelligents.

Discussions similaires

  1. Jointure qui ne renvoie pas tous les enregistrements
    Par rayonx dans le forum Langage SQL
    Réponses: 12
    Dernier message: 19/07/2024, 10h33
  2. Réponses: 3
    Dernier message: 30/10/2013, 19h49
  3. je ne comprend pas un parse error
    Par bibi_64 dans le forum C
    Réponses: 3
    Dernier message: 21/09/2005, 15h00
  4. Réponses: 2
    Dernier message: 13/01/2005, 00h08
  5. Le compilateur ne trouve pas glut32.dll
    Par Vathal dans le forum GLUT
    Réponses: 3
    Dernier message: 26/01/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