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 :

Erreur compilation - surcharge opérateur


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Par défaut Erreur compilation - surcharge opérateur
    Bonjour à tous.

    Je bloque sur qqch qui paraît simplissime, mais je n'arrive pas à trouver la source du problème.
    J'essaie tout simplement de surcharger un opérateur + pour un type que j'ai définit.

    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
    #include <iostream>
    #include <cassert>
    #include <math.h>
     
    typedef unsigned char PixelNB;
    typedef double PixelFloat;
     
    inline PixelNB operator*(const PixelNB& pix, double a){
    		assert(a>=0);
    		int gris=std::min( static_cast< int >(round(a*pix)) , 255 );
    		PixelNB pix_res=gris;
    		return pix_res;
    };
     
    int main( int argc, char* argv[] ){
    		PixelNB pixNB=77;
    		std::cout << "Hello World !" << std::endl;
    }
    A la compilation :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    main.cc:10:16: error: overloaded 'operator*' must have at least one parameter of class or enumeration type
    inline PixelNB operator*(const PixelNB& pix, double a){
                   ^
    1 error generated.
    Mon compilateur (sous MAC) :
    Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
    Target: x86_64-apple-darwin12.6.0


    Le but pour la suite serait de définir cet opérateur pour d'autre type de pixel et de pouvoir ajouter ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    inline PixelFloat operator*(const PixelFloat& pix, double a){
    		return a*pix;
    };
     
    template <typename PixelType>
    inline PixelType operator*(double a, const PixelType& pix){ return pix*a; };
    Merci de votre aide.

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 147
    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 147
    Billets dans le blog
    4
    Par défaut
    Salut,

    comme l'indique l'erreur, tu ne peux surcharger un opérateur que pour un type utilisateur. Un typedef n'est pas un type utilisateur.
    Il te faut une class/struct/union ou enum. Encore une fois, c'est écrit dans le message d'erreur.
    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
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    un typedef n'est pas un nouveau type.
    C'est un nouveau nom de type.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    typedef unsigned char PixelNB;
    PixelNB operator*(const PixelNB& pix, double a);
    Ceci est strictement identique à:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    unsigned char operator*(const unsigned char& pix, double a);
    aucun des deux types unsigned char et double n'est un "user defined type", c'est à dire une classe, une structure, une enum ou une union.

  4. #4
    Membre Expert

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Par défaut
    Donc en gros si je vous suis bien je suis en train de vouloir redéfinir un opérateur interne au C++ (le produit d'un uchar avec un double).
    Est-ce possible de le faire ? Visiblement non par le moyen que j'essaie, mais y-a-t-il un autre moyen ?

    Si j'englobe la chose dans un struct, ou une classe (je ne maitrise pas du tout les enum, mais je ne pense pas que la solution réside là):

    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
    class PixelNB{
    public:
    	template <typename T>
    	PixelNB( T c ):_data(c){};
     
    	unsigned char data() const { return _data; };
    	void PrintPixel(){ std::cout << (int) _data << std::endl ; };
     
    private:	
    	unsigned char _data;
    };
     
    PixelNB operator+( const PixelNB& pix1, const PixelNB& pix2  ){ 
    	return PixelNB( pix1.data()+pix2.data() ); };
     
    inline PixelNB operator*(const PixelNB& pix, double a){
    		assert(a>=0);
    		int gris=std::min( static_cast< int >(round(a*pix.data())) , 255 );
    		PixelNB pix_res=gris;
    		return pix_res;
    };
     
    int main( int argc, char* argv[] ){
    		PixelNB pix1(77);
    		PixelNB pix2(43);
     
    		pix1.PrintPixel();
    		PixelNB pix3( pix1+pix2 );
    		pix3.PrintPixel();
    		PixelNB pix4( pix1*0.3 );
    		pix4.PrintPixel();
    }
    Alors ca me complique beaucoup les choses car je dois réécrire tous les autres opérateurs (du style l'affection par =, somme de deux uchar, produit, etc ... ) en version unaire et binaire, sans compter les cast ... Et pour mon type PixelFloat qui devra devenir lui aussi une classe ce sera pareil. Et si j'ai un 3eme type de pixel, ca va vite devenir très très lourd. Donc je ne pense pas que la classe soit la bonne solution.

  5. #5
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2010
    Messages
    517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

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

    Informations forums :
    Inscription : Avril 2010
    Messages : 517
    Par défaut
    Salut,

    Heureusement que l'on ne peut pas redéfinir des opérateurs sur des types de bases! Image un peu le bazar que cela produirait pour les autres utilisateurs (s'il y en a... mais ça c'est une autre histoire).

    Sinon, pour ton problème de PixelNB et PixelFloat, tu peux tout simplement faire un template:

    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
    template<typename TYPE>
    class PixelT
    {
    public:
      PixelT(const T & c) : m_data(static_cast<T>(c)
      {}
     
      virtual ~PixelT()
      {}
     
    private:
       T m_data;
    };
     
    template<typename TYPE>
    PixelT<TYPE> operator*(const PixelT<TYPE> & pix, double a)
    {
       assert(a>=0); // Préfère l'utilisation d'exception, ça évite de planter ton programme
       TYPE gris=std::min( static_cast< TYPE >(round(a*pix)) , static_cast<TYPE>(255) );
       Pixel<TYPE> pix_res(gris);
       return pix_res;
    }
     
     
    typedef PixelT<unsigned char> PixelNB;
    typedef PixelT<float> PixelFloat;
    typedef PixelT<double> PixelDouble;

  6. #6
    Membre Expert

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Par défaut
    En partant de ton code darkman, voici quelques modifications qui permettent de le rendre compilable :
    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
    template<typename TYPE>
    class PixelT{
    public:
    	template<typename T>
      PixelT(const T & c) : m_data(static_cast<TYPE>(c)){};
      void PrintPixel();
      virtual ~PixelT(){};
     
      TYPE data() const { return m_data; };
     
    private:
       TYPE m_data;
    };
     
    template<typename TYPE>
    PixelT<TYPE> operator*(const PixelT<TYPE> & pix, double a){
       assert(a>=0); // Préfère l'utilisation d'exception, ça evite de planter ton programme
       TYPE gris=std::min( static_cast< TYPE >(round(a*pix.data())) , static_cast<TYPE>(255) );
       PixelT<TYPE> pix_res(gris);
       return pix_res;
    }
     
    template<typename TYPE>
    void PixelT<TYPE>::PrintPixel(){ std::cout << m_data << std::endl ; }
     
    template<>
    void PixelT<unsigned char>::PrintPixel(){ std::cout << (int) m_data << std::endl ; }
     
    typedef PixelT<unsigned char> PixelNB;
    typedef PixelT<float> PixelFloat;
    typedef PixelT<double> PixelDouble;
     
    int main( int argc, char* argv[] ){
     		PixelNB pix1(77);
     		PixelNB pix2(43);
     
     		pix1.PrintPixel();
    		//PixelNB pix3( pix1+pix2 );
    		//pix3.PrintPixel();
    		PixelNB pix4( pix1*0.3 );
    		pix4.PrintPixel();
    }
    Donc effectivement ca réponds au problème : Quelle structure adopter ?
    Par contre ca m'oblige à redéfinir tous les autres opérateurs encore ...
    Du style pour l'addition:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    template<typename TYPE>
    PixelT<TYPE> operator+( const PixelT<TYPE>& pix1, const PixelT<TYPE>& pix2  ){ 
    return PixelT<TYPE>( pix1.data()+pix2.data() ); }
    Dans mon cas je veux juste modifier ce qui se passe lors de la multiplication par un scalaire.
    Pour tous les autres opérateurs (dont j'ai besoin également) je veux garder le comportement natif.

    Question naive du coup qui me vient à l'esprit : Ai-je moyen de templatiser l'opérateur lui-même ?
    Ca permettrait de créer une méthode qui, pour tout opérateur, appliquerait les effets de l'opération sur le m_data.
    Et je pourrais spécialiser le cas produit par un scalaire.

  7. #7
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2010
    Messages
    517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

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

    Informations forums :
    Inscription : Avril 2010
    Messages : 517
    Par défaut
    Citation Envoyé par lg_53 Voir le message
    Par contre ca m'oblige à redéfinir tous les autres opérateurs encore ...
    Oui mais en même temps, je ne pense pas que tu en ai 50 à surcharger: +, -, *, /, +=, -=, *=, /=.
    De plus, même si tu ne les redéfinis pas (tous voire aucun), tu n'as juste qu'à appeler ton accesseur data() et faire l'opération dessus.

    Citation Envoyé par lg_53 Voir le message
    Question naive du coup qui me vient à l'esprit : Ai-je moyen de templatiser l'opérateur lui-même ?
    Ca serait vraiment une bonne idée mais malheureusement ça n'est pas possible (à ma connaissance). Mais bon, je ne vois pas comment cela serait possible. Certains opérateurs renvoient des booléens, d'autres un objet etc...

    Edit: l'opérateur de conversion comme dit Bousk est une bonne idée et simple à mettre en place.

  8. #8
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 147
    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 147
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par lg_53 Voir le message
    Alors ca me complique beaucoup les choses car je dois réécrire tous les autres opérateurs (du style l'affection par =, somme de deux uchar, produit, etc ... ) en version unaire et binaire, sans compter les cast ...
    Ou alors tu la joue malin. Tu fais un opérateur de conversion, et toutes les opérations que tu ne redéfinis pas seront possible via la conversion implicite.
    Citation Envoyé par lg_53 Voir le message
    Et pour mon type PixelFloat qui devra devenir lui aussi une classe ce sera pareil. Et si j'ai un 3eme type de pixel, ca va vite devenir très très lourd.
    Encore un peu de malinerie : 3 trucs similaires dont seul le type change ? Hmmmm ça serait pas du template ça ?
    Citation Envoyé par lg_53 Voir le message
    Donc je ne pense pas que la classe soit la bonne solution.
    Tu es libre de penser, mais c'est la seule solution.
    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.

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

Discussions similaires

  1. Erreur de segmentation surcharge opérateur []
    Par Nicoclem dans le forum C++
    Réponses: 3
    Dernier message: 17/04/2008, 18h05
  2. surcharge opérateur erreur compilation
    Par damien77 dans le forum C++
    Réponses: 8
    Dernier message: 21/02/2007, 17h59
  3. [Débutant]Erreur compilation !
    Par gandalf_le_blanc dans le forum AWT/Swing
    Réponses: 23
    Dernier message: 30/08/2004, 14h23
  4. Trop de message d'erreurs: compilation KO
    Par jeannot27 dans le forum C++Builder
    Réponses: 6
    Dernier message: 21/01/2004, 16h45
  5. Erreur compilation DX8.1 VC++ 6
    Par d.vidal dans le forum DirectX
    Réponses: 1
    Dernier message: 10/09/2003, 09h04

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