Problème de syntaxe (opérateur << enum dans class) [Résolu]

Polack77 1100 Messages postés mercredi 22 mars 2006Date d'inscription 15 avril 2018 Dernière intervention - 3 févr. 2018 à 14:27 - Dernière réponse : Polack77 1100 Messages postés mercredi 22 mars 2006Date d'inscription 15 avril 2018 Dernière intervention
- 7 févr. 2018 à 16:19
Bonjour,

Bonjour,

J'ai un problème de syntaxe. En même temps la façon d'on je veux construire ma classe n'est peut être pas correcte... Mais je vois pas trop pourquoi...

Alors je veux déclarer une classe qui contient un enum public (jusque là tout vas bien).
Ajouter :
un opérateur << spécifique à mon enum histoire de pouvoir l'utiliser seul si ça m'éclate //<- c'est là que ça coince
et un opérateur << pour ma classe

Petite nuance, j'aimerais que mon opérateur spécifique soit DANS ma classe (pck j'aime bien :p).
Seconde nuance pas de ".h" (oui c'est pas super top mais c'est comme ça dans ce cas précis)

Donc je fait :
//###############################################################################################################################################
// CLASS EXEMPLE CODES SOURCES
//###############################################################################################################################################
//classe exemple
class cl_ExempleCS
{
//==================================================================================
// PUBLIC
//==================================================================================
public:
    //----------------------------------------
    //enum de type d'unité
    //----------------------------------------
    enum en_MonEnumeration
    {
        eME_NoDefine = -1,
     eME_Premier,
     eME_Second,
     // ...
    };
    //----------------------------------------
    // OPERATOR << de enum en_MonEnumeration
    //----------------------------------------
    std::ostream& operator << (std::ostream& O, enum en_MonEnumeration& ValEnum)
    {
        switch (ValEnum)
        {
            case veh_NoDefine:
                O << "NoDefine";
                break;
            case eME_Premier:
                O << "Premier";
                break;
            case eME_Second:
                O << "Second";
                break;
            default:
                O << "ERREUR !";
                break;
        }
        
        return O;
    }
//==================================================================================
// PRIVATE
//==================================================================================
private:
    enum en_MonEnumeration m_ValEnum;
    //...

//==================================================================================
// PUBLIC
//================================================================================== 
public:
    // ...
    //----------------------------------------
    // OPERATOR <<
    //----------------------------------------
    std::ostream& operator << (std::ostream& O)
    {
        O << "ValEnum=" <<  this->m_ValEnum <<  ";";
        // ...
        
        return O;
    }
};


Et mon compilo râle :

/tmp/######.cpp:50:80: error: ‘std::ostream& cl_ExempleCS::operator<<(std::ostream&, cl_ExempleCS::en_MonEnumeration&)’ must take exactly one argument
std::ostream& operator << (std::ostream& O, enum en_MonEnumeration& ValEnum)
^


Mais alors, comment je fait pour lui déclarer le type qu'il attend pour le 1er opérateur << ?

Merci d'avance :)
Afficher la suite 

Votre réponse

5 réponses

cptpingu 3794 Messages postés dimanche 12 décembre 2004Date d'inscriptionModérateurStatut 10 juin 2018 Dernière intervention - 4 févr. 2018 à 11:21
0
Merci
Bonjour.

Ce que tu veux faire est compliqué. Il n'existe que deux signatures possibles pour operator<<, une avec un seul argument qui se met dans la classe, et une avec deux arguments qui se met en dehors d'une classe.
Un enum étant un entier, et vu qu'il n'est pas possible de redéfinir un operator pour un type pod, ce que tu veux faire est impossible.

Deux solutions, néanmoins:
  • Tu ne gardes que le operator<< interne à ta classe, et tu fournis une fonction print(ostream, ton_enum).
  • Tu fais une sous classe qui contient uniquement ton enum et un operator<< interne. Tu redéfinis le constructeur de copie, l'operator= et l'operator de conversion, pour passer d'un int à ta sous-classe interne. Ça fonctionnera, mais ça te fera un overhead sur ton enum...

Commenter la réponse de cptpingu
Polack77 1100 Messages postés mercredi 22 mars 2006Date d'inscription 15 avril 2018 Dernière intervention - 4 févr. 2018 à 13:55
0
Merci
Merci pour ta réponse :)

Oui, ton idée me semble bien :clap: . Et je vois pas pourquoi ça ne marcherais pas

J'ai testé, et probablement fait quelque-chose de travers. J’avoue ne pas comprendre l'erreur (on dirait qu'il ne trouve pas mon opérateur spécifique à ma "sous-classe", pourtant :/).

En "dépannage", j'ai fait deux opérateurs "<<" hors de ma classe (un sur l'enum, l'autre sur la classe) et ça fonctionne très bien. Mais c'est vrais que je préférerais faire entrer tout ça directement dans ma classe (oui c'est pas nécessaire, mais bon, j'aime bien l'idée -puis j'aime pas rester sur un échec :p-)

Code :
//###############################################################################################################################################
// CLASS EXEMPLE CODES SOURCES
//###############################################################################################################################################
//classe exemple
class cl_ExempleCS
{
//==================================================================================
// PUBLIC
//==================================================================================
public:
    
class cl_TestForEnum
    {
    //==================================================================================
    // PUBLIC
    //==================================================================================
    public:
        //----------------------------------------
        //enum exemple
        //----------------------------------------
        enum en_MonEnumeration
        {
            eME_NoDefine = -1,
            eME_Premier,
            eME_Second,
         // ...
        };
        
    //==================================================================================
    // PRIVATE
    //==================================================================================
    private:
        enum en_MonEnumeration m_value;
        
    //==================================================================================
    // PUBLIC
    //==================================================================================
    public:
        //----------------------------------------
        // Constructeur
        //----------------------------------------
        cl_TestForEnum() : m_value(en_MonEnumeration::eME_NoDefine)
        {
        }
        //----------------------------------------
        // OPERATOR = (enum) <- tien on devrait pourvoir faire un template là
        //----------------------------------------
        enum en_MonEnumeration operator = (enum en_MonEnumeration value)
        {
            return (this->m_value = value);
        }
        //----------------------------------------
        // OPERATOR = (int)
        //----------------------------------------
        int operator = (int value)
        {
            return (this->m_value = (enum en_MonEnumeration)value);
        }
        //----------------------------------------
        // OPERATOR == (int)
        //----------------------------------------
        bool operator == (int value)
        {
            return (this->m_value == (enum en_MonEnumeration)value);
        }
        //----------------------------------------
        // OPERATOR << de enum en_MonEnumeration
        //----------------------------------------
        std::ostream& operator << (std::ostream& O)
        {
            switch (this->m_value)
            {
                case eME_NoDefine:
                    O << "NoDefine";
                    break;
                case eME_Premier:
                    O << "Premier";
                    break;
                case eME_Second:
                    O << "Second";
                    break;
                default:
                    O << "ERREUR (value=" << this->m_value << ") !";
                    break;
            }
            
            return O;
        }
    };
    
//==================================================================================
// PRIVATE
//==================================================================================
private:
    cl_TestForEnum m_ValEnum;
    //...

//==================================================================================
// PUBLIC
//================================================================================== 
public:
    //----------------------------------------
    // Constructeur
    //----------------------------------------
    cl_ExempleCS() : m_ValEnum()
    {
    }
    
    // ...
    //----------------------------------------
    // OPERATOR <<
    //----------------------------------------
    std::ostream& operator << (std::ostream& O)
    {
        O << "ValEnum=" << this->m_ValEnum <<  ";";
        // ...
        
        return O;
    }
};


Mon erreur :
/tmp/Answer.cpp: In member function ‘std::ostream& cl_ExempleCS::operator<<(std::ostream&)’:
/tmp/Answer.cpp:150:25: error: no match for ‘operator<<’ (operand types are ‘std::basic_ostream<char>’ and ‘cl_ExempleCS::cl_TestForEnum’)
         O << "ValEnum=" << this->m_ValEnum <<  ";";
         ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~
In file included from /usr/include/c++/7/iostream:39:0,
                 from /tmp/Answer.cpp:4:
/usr/include/c++/7/ostream:108:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ostream_type& (*)(std::basic_ostream<_CharT, _Traits>::__ostream_type&)) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(__ostream_type& (*__pf)(__ostream_type&))
       ^~~~~~~~
/usr/include/c++/7/ostream:108:7: note:   no known conversion for argument 1 from ‘cl_ExempleCS::cl_TestForEnum’ to ‘std::basic_ostream<char>::__ostream_type& (*)(std::basic_ostream<char>::__ostream_type&) {aka std::basic_ostream<char>& (*)(std::basic_ostream<char>&)}’

...
annot convert ‘((cl_ExempleCS*)this)->cl_ExempleCS::m_ValEnum’ (type ‘cl_ExempleCS::cl_TestForEnum’) to type ‘const char*’
         O << "ValEnum=" << this->m_ValEnum <<  ";";
                            ~~~~~~^~~~~~~~~
In file included from /usr/include/c++/7/iostream:39:0,
                 from /tmp/Answer.cpp:4:
/usr/include/c++/7/ostream:569:5: note: candidate: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, const signed char*)
     operator<<(basic_ostream<char, _Traits>& __out, const signed char* __s)
     ^~~~~~~~
/usr/include/c++/7/ostream:569:5: note:   template argument deduction/substitution failed:
/tmp/Answer.cpp:150:34: note:   cannot convert ‘((cl_ExempleCS*)this)->cl_ExempleCS::m_ValEnum’ (type ‘cl_ExempleCS::cl_TestForEnum’) to type ‘const signed char*’
         O << "ValEnum=" << this->m_ValEnum <<  ";";
                            ~~~~~~^~~~~~~~~
In file included from /usr/include/c++/7/iostream:39:0,
                 from /tmp/Answer.cpp:4:
/usr/include/c++/7/ostream:574:5: note: candidate: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, const unsigned char*)
     operator<<(basic_ostream<char, _Traits>& __out, const unsigned char* __s)
     ^~~~~~~~
/usr/include/c++/7/ostream:574:5: note:   template argument deduction/substitution failed:
/tmp/Answer.cpp:150:34: note:   cannot convert ‘((cl_ExempleCS*)this)->cl_ExempleCS::m_ValEnum’ (type ‘cl_ExempleCS::cl_TestForEnum’) to type ‘const unsigned char*’
         O << "ValEnum=" << this->m_ValEnum <<  ";";
                            ~~~~~~^~~~~~~~~
In file included from /usr/include/c++/7/iostream:39:0,
                 from /tmp/Answer.cpp:4:
/usr/include/c++/7/ostream:682:5: note: candidate: template<class _Ostream, class _Tp> typename std::enable_if<std::__and_<std::__not_<std::is_lvalue_reference<_Tp> >, std::__is_convertible_to_basic_ostream<_Ostream>, std::__is_insertable<typename std::__is_convertible_to_basic_ostream<_Tp>::__ostream_type, const _Tp&, void> >::value, typename std::__is_convertible_to_basic_ostream<_Tp>::__ostream_type>::type std::operator<<(_Ostream&&, const _Tp&)
     operator<<(_Ostream&& __os, const _Tp& __x)
     ^~~~~~~~
/usr/include/c++/7/ostream:682:5: note:   template argument deduction/substitution failed:
/usr/include/c++/7/ostream: In substitution of ‘template<class _Ostream, class _Tp> typename std::enable_if<std::__and_<std::__not_<std::is_lvalue_reference<_Tp> >, std::__is_convertible_to_basic_ostream<_Ostream>, std::__is_insertable<typename std::__is_convertible_to_basic_ostream<_Tp>::__ostream_type, const _Tp&, void> >::value, typename std::__is_convertible_to_basic_ostream<_Tp>::__ostream_type>::type std::operator<<(_Ostream&&, const _Tp&) [with _Ostream = std::basic_ostream<char>&; _Tp = cl_ExempleCS::cl_TestForEnum]’:
/tmp/Answer.cpp:150:34:   required from here
/usr/include/c++/7/ostream:682:5: error: no type named ‘type’ in ‘struct std::enable_if<false, std::basic_ostream<char>&>’

Commenter la réponse de Polack77
cptpingu 3794 Messages postés dimanche 12 décembre 2004Date d'inscriptionModérateurStatut 10 juin 2018 Dernière intervention - 4 févr. 2018 à 17:30
0
Merci
Dans ce cas, il va falloir jouer avec le mot clé friend, et diviser la fonction de print en deux (une fonction friend privée ne peut accéder qu'à des données statiques).

Ça donnerait ceci:
#include <iostream>

class cl_ExempleCS
{
public:
  class cl_TestForEnum
  {
  public:
    enum en_MonEnumeration
      {
        eME_NoDefine = -1,
        eME_Premier,
        eME_Second,
      };

    cl_TestForEnum() : m_value(en_MonEnumeration::eME_NoDefine){}

    void print(std::ostream& out) const
    {
      switch (m_value)
      {
        case eME_NoDefine:
          out << "NoDefine";
          break;
        case eME_Premier:
          out << "Premier";
          break;
        case eME_Second:
          out << "Second";
          break;
        default:
          out << "ERREUR (value=" << m_value << ") !";
          break;
      }
    }

    friend std::ostream& operator<<(std::ostream& out, const cl_TestForEnum& obj)
    {
      obj.print(out);
      return out;
    }

  private:
    enum en_MonEnumeration m_value;
  };

public:
  cl_ExempleCS() : m_ValEnum(){}

  void print(std::ostream& out) const
  {
    out << "ValEnum=" << m_ValEnum <<  ";";
  }

  friend std::ostream& operator<<(std::ostream& out, const cl_ExempleCS& obj)
  {
    obj.print(out);
    return out;
  }

private:
  cl_TestForEnum m_ValEnum;
};

int main() {
  cl_ExempleCS test;
  std::cout << test << std::endl;

  return 0;
}

Commenter la réponse de cptpingu
Dalfab 346 Messages postés dimanche 7 février 2016Date d'inscription 14 juillet 2018 Dernière intervention - 4 févr. 2018 à 17:41
0
Merci
En définissant membre un opérateur binaire, le paramètre correspond au membre de droite. Dans le cas le l'opérateur
<<
l'ostream est à utiliser à gauche de
<<
. On ne peut donc pas définir cet opérateur comme un membre, il faut impérativement définir une fonction externe ayant deux paramètres.
Commenter la réponse de Dalfab
Polack77 1100 Messages postés mercredi 22 mars 2006Date d'inscription 15 avril 2018 Dernière intervention - Modifié par Polack77 le 7/02/2018 à 16:22
0
Merci
Je trouve un peu de temps à accorder à ce sujet ^^

Bah c'est pas mal ta solution cptpingu. Ça marche même très bien pour l'opérateur <<.
Par contre plus possible de faire un switch sur l'objet (ou j'ai pas trouvé comment). L'enum perd quand même beaucoup de son intérêt. Et même si ça doit être possible, ré-écrire le c++ par caprice (je voulais faire entrer cet opérateur dans ma classe) est sans doute exagéré.

Résultat Delfab à raison, si on veut déclarer un opérateur << sur un enum, il faut nécessairement le déclarer comme une fonction externe. C'est simplement la syntaxe "normale" du c++

Merci du temps investie à vous deux :)

PS :
Tout ça c'était pour organiser mon code et faire des messages de debug simple à écrire dans https://www.codingame.com/ide/puzzle/mean-max
Commenter la réponse de Polack77

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.