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 :

enable_if pour activer une fonction non template


Sujet :

C++

  1. #1
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    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 189
    Points : 17 141
    Points
    17 141
    Par défaut enable_if pour activer une fonction non template
    Bonjour à tous

    Je construis actuellement une bibliothèque pleine de builders.
    Comme ils sont extrêmement répétitifs, j'ai opté pour une macro générant un champ privé et un setter
    L'idée est de pouvoir chainer les appels, à la façon du "named parameter".

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    #define MACRO_BUILDER_PROPERTY(Self, Type, Name) \
    private:\
    	Type m_##Name;\
    public:\
    	Self& Name(Type const& Name) {m_##Name = Name; return *this;}
    Supposons, la classe suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class BiduleBuilder {
    MACRO_BUILDER_PROPERTY(BiduleBuilder, int, valeur)
    MACRO_BUILDER_PROPERTY(BiduleBuilder, optional<std::string>, nom)
     
    public:
    	Bidule build();
    };
    Cela génère:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    private:class BiduleBuilder {
    	int m_valeur;
    public:
    	BiduleBuilder& valeur(int const& valeur) {m_valeur = valeur; return *this;}
     
    private:
    	optional<std::string> m_nom;
    public:
    	BiduleBuilder& nom(optional<std::string> const& nom) {m_nom = nom; return *this;}
     
    public:
    	Bidule build();
    };
    Cela permet alors d'écrire BiduleBuilder().valeur(1).nom(std::string("coin coin")).build();.

    Jusque là, tout va bien. Les services rendus sont satisfaisant.

    Mais pour des raisons d'ergonomies, on voudrait pouvoir se passer de la construction explicite du std::string dans le cas d'un optional<std::string> (ou en fait de tout optional<...>)
    Et c'est là que le bât blesse.

    La seule solution que permet optional (de boost ou prochainement de std), c'est de fournir aussi BiduleBuilder& nom(std::string const& nom);.
    Donc, il faut que la macro réfléchisse comme une grande pour l'ajouter si besoin est, ou qu'elle ajoute une fonction dont l'appel sera impossible si on n'est pas dans le cas d'une optional.

    J'ai bien pensé à enable_if, mais ce n'est possible que sur une template.

    Que me conseillez-vous?
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  2. #2
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    Ne serait-ce pas plus simple de laisser tous passer avec une référence universelle pour que l'erreur de compilation arrive sur l'affectation dans la fonction ?

    template<class T> Self& Name(T && x) {m_##Name = std::forward<T>(x); return *this;}.

    Il y a aussi std::is_convertible, mais c'est effectivement possible qu'avec une template.

  3. #3
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 470
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 470
    Points : 6 107
    Points
    6 107
    Par défaut
    De mon côté, je n'ai rien de mieux que 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
    #define MACRO_BUILDER_PROPERTY(Self, Type, Name) \
    private:\
    	Type m_##Name;\
    public:\
    	Self& Name(Type const& Name) {m_##Name = Name; return *this;}
     
    #define MACRO_BUILDER_OPTIONAL_PROPERTY(Self, Type, Name) \
    private:\
    	boost::optional<Type> m_##Name;\
    public:\
    	Self& Name(boost::optional<Type> const& Name) {m_##Name = Name; return *this;}\
    	Self& Name(Type const& Name)                  {m_##Name = Name; return *this;}
     
    class BiduleBuilder {
    	MACRO_BUILDER_PROPERTY(BiduleBuilder, int, valeur)
    	MACRO_BUILDER_OPTIONAL_PROPERTY(BiduleBuilder, std::string, nom)
    };
     
    // Équivaut à :
    /*
    class BiduleBuilder {
    private:
    	int m_valeur;
    public:
    	BiduleBuilder& valeur(int const& valeur) {m_valeur = valeur; return *this;}
     
    private:
    	boost::optional<std::string> m_nom;
    public:
    	BiduleBuilder& nom(boost::optional<std::string> const& nom) {m_nom = nom; return *this;}
    	BiduleBuilder& nom(std::string const& nom)                  {m_nom = nom; return *this;}
    };
    */
     
    int _tmain(int argc, _TCHAR* argv[])
    {
    	BiduleBuilder foo;
    	foo.valeur(1).nom("coin coin"); // pas besoin d'écrire string
    	foo.nom(boost::none);
    	return 0;
    }

  4. #4
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    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 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Citation Envoyé par jo_link_noir Voir le message
    Ne serait-ce pas plus simple de laisser tous passer avec une référence universelle pour que l'erreur de compilation arrive sur l'affectation dans la fonction ?

    template<class T> Self& Name(T && x) {m_##Name = std::forward<T>(x); return *this;}.

    Il y a aussi std::is_convertible, mais c'est effectivement possible qu'avec une template.
    C'est possible en effet, mais je ne sais pas jusqu'à quel point c'est possible en C++03 (en fait gcc 4.4.7)
    Ca doit être faisable avec une const&, mais pour "éviter les templates dans des macros" (dixit mon responsable), je suis parti sur la solution de Pyramidev

    Merci à tous les deux pour vos avis.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

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

Discussions similaires

  1. activer une fonction d'une page contenue dans une popup.
    Par manutudescends dans le forum Général JavaScript
    Réponses: 3
    Dernier message: 16/08/2006, 14h32
  2. Réponses: 20
    Dernier message: 21/06/2006, 20h44
  3. Utiliser une touche pour appeller une fonction
    Par Hide dans le forum Langage
    Réponses: 2
    Dernier message: 13/10/2005, 16h59
  4. Réponses: 7
    Dernier message: 10/09/2005, 16h49
  5. [DLL] problème pour appeler une fonction d'une DLL
    Par bigboomshakala dans le forum MFC
    Réponses: 34
    Dernier message: 19/07/2004, 11h30

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