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 :

Vous gérez comment les noms de classe template qui deviennent longs ?


Sujet :

C++

  1. #1
    Membre à l'essai
    Femme Profil pro
    Inscrit en
    Mars 2013
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France

    Informations forums :
    Inscription : Mars 2013
    Messages : 8
    Points : 10
    Points
    10
    Par défaut Vous gérez comment les noms de classe template qui deviennent longs ?
    Bonjour,
    Je suis développeur C++/Qt et je me demandais quelles sont les manières de gérer le noms de class template qui deviennent long. Par exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    QList<QSharedPointer<AbstractParamsModel>>
    ParamsListSelectionModel::selectedParamsMerged(
            const QString &lang)
    {
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    QMultiMap<QString, SortedMap<QString, double>>
    OrderManager::earningConvertedByArticles(
            const QDate &begin, const QDate &end) const
    {
    Trouvez-vous cela normal? Peut-on faire mieux? Que faites-vous dans ces situations?
    Merci d'avance,
    Cédric

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Salut,

    tu peux faire un typedef ou using afin de donner un nom plus clair et concis.
    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 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
    C'est ce que je recommande tout le temps.

    Il faut distinguer la forme (QMultiMap<QString, SortedMap<QString, double>>) du fond (earningConvertedByArticles_type).

    La forme dit comment lire la chose, c'est uniquement intéressant pour la technique (la compilabilité), tandis que la forme explique ce que c'est.
    Ce ne sont pas n'importe quelles clés ou valeurs. Cela dit, il manque un niveau d'explication, parce qu'il y a deux niveaux de clés.

    La forme en elle même est inintéressante à la compréhension générale.
    Personnellement, je vais même plus loin, en faisant de tels alias même pour des types simples (id_type, name_type, price_type, etc).
    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

  4. #4
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 473
    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 473
    Points : 6 113
    Points
    6 113
    Par défaut Typage fort
    Encore plus fort que les alias : le typage fort.
    Par exemple, pour représenter un code d'utilisateur et un code de configuration, au lieu d'utiliser le type int, on crée deux types distincts, UserCode et ConfigCode. Aucun n'est implicitement convertible en l'autre.

    Avantages :
    • On récupère les avantages des alias. Par exemple, std::map<UserCode, ConfigCode> évoque plus précisément ce qu'il représente que std::map<int, int>.
    • On a un autre avantage en bonus : le compilateur fait plus de contrôles. Par exemple, avec une fonction void link(int userCode, int configCode), on peut se tromper et appeler par mégarde link(configCode, userCode). Par contre, avec une fonction void link(UserCode userCode, ConfigCode configCode), ce genre d'erreur d'étourderie provoque une erreur de compilation.


    Mais comme les types forts comme UserCode et ConfigCode risquent d'avoir un peu tous le même code (à moins qu'ils aient des invariants distincts), il convient de factoriser leur code grâce aux templates :
    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
    #include <functional>
    #include <unordered_map>
     
    template<class T, class FlagForDisambiguation>
    class StrongType
    {
    public:
    	using value_type = T;
    	constexpr explicit StrongType() : m_value() {}
    	template<class U = T>
    	constexpr explicit StrongType(U&& value) : m_value(std::forward<U>(value)) {}
    	constexpr const T& value() const {return m_value;}
    	constexpr bool operator==(const StrongType& other) const {return m_value == other.m_value;}
    	constexpr bool operator< (const StrongType& other) const {return m_value <  other.m_value;}
    	constexpr bool operator> (const StrongType& other) const {return other   <  *this;}
    	constexpr bool operator<=(const StrongType& other) const {return !(other <  *this);}
    	constexpr bool operator>=(const StrongType& other) const {return !(*this <  other);}
    private:
    	T m_value;
    };
     
    template<class StrongTypeT>
    struct StrongTypeHash
    {
    	size_t operator()(const StrongTypeT& param) const
    	{
    		return std::hash<typename StrongTypeT::value_type>()(param.value());
    	}
    };
     
    template<class StrongTypeKey, class Value>
    using StrongHashMap = std::unordered_map<StrongTypeKey, Value, StrongTypeHash<StrongTypeKey>>;
     
    // Exemple d'utilisation :
    using UserCode   = StrongType<int, struct FlagUserCode>;
    using ConfigCode = StrongType<int, struct FlagConfigCode>;

  5. #5
    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
    J'approuve totalement.
    Même si j'ai tendance à préférer les alias pour les structures un peu complexes, membres privés d'une classe.

    Petite question:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    using UserCode  = StrongType<int, struct FlagUserCode>;
    C'est légal, de déclarer une struct dans un paramètre template?
    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

  6. #6
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 678
    Points
    13 678
    Billets dans le blog
    1
    Par défaut
    Hé mais c'est vachement cool ce StrongType ! Je me posais ces derniers temps la question pour faire ça justement : des typages forts sur des entiers

    J'ai plusieurs questions sur ce code en revanche....

    1) A quoi sert le 2e paramètre class FlagForDisambiguation ?

    2) A quoi sert using value_type = T; ?

    3) Pourquoi le constructeur par référence est-il template ? L'affectation à T donne t-elle une valeur par défaut au paramètre template (comme pour un paramètre formel de fonction) ?

  7. #7
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par Bktero Voir le message
    1) A quoi sert le 2e paramètre class FlagForDisambiguation ?
    Comme le code l'indique c'est pour enlever l'ambiguité.
    Sans ça, tous les StrongTypes<int> sont le même type et l'intérêt devient nul.

    Citation Envoyé par Bktero Voir le message
    2) A quoi sert using value_type = T; ?
    C'est un alias sur T. Alias non utilisé ici.

    Citation Envoyé par Bktero Voir le message
    3) Pourquoi le constructeur par référence est-il template ? L'affectation à T donne t-elle une valeur par défaut au paramètre template (comme pour un paramètre formel de fonction) ?
    C'est un constructeur qui prend une valeur pour l'assigner directement à ta classe.
    Je suis pas sûr que le template soit utile ici, il suffirait d'avoir un constructeur StrongType(T&& value) à priori.
    Peut-être que ça aide le compilo pour qqs conversions implicites ?
    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.

  8. #8
    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
    En fait, ca ne couvre que les conversions implicites. Les constructeurs par copie et par déplacement sont quand même générés.

    C'est un peu traitre.
    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

  9. #9
    Membre chevronné Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 044
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 044
    Points : 2 239
    Points
    2 239
    Par défaut
    Pour les entiers pas besoin de chercher compliqué...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    enum class UserCode;
    enum class ConfigCode;
    UserCode u = (UserCode)0;
    ConfigCode c = (ConfigCode)0;
    ConfigCode a = u; // Erreur ici
    UserCode b = c; //Erreur ici
    Sinon un typedef typename ou usingsuffirais pour raccourcir ton nom.

    Sinon si tu as des contraintes de typage forte... bas fait une class ou une struct. Ça doit se justifier par le simple fait que le typage soit fort...
    Homer J. Simpson


  10. #10
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 473
    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 473
    Points : 6 113
    Points
    6 113
    Par défaut
    Citation Envoyé par ternel Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    using UserCode  = StrongType<int, struct FlagUserCode>;
    C'est légal, de déclarer une struct dans un paramètre template?
    Ça compile avec GCC 7.1.0, mais j'avoue ne pas avoir vérifié dans la norme.

    Citation Envoyé par Bktero Voir le message
    A quoi sert le 2e paramètre class FlagForDisambiguation ?
    Les constructeurs et affectations de copie et mouvement générés par le compilateur ont un paramètre StrongType qui doit avoir à la fois le même T et le même FlagForDisambiguation. C'est ce qui empêche, par exemple, de convertir implicitement UserCode (alias de StrongType<int, struct FlagUserCode>) en ConfigCode (alias de StrongType<int, struct FlagConfigCode>).

    Citation Envoyé par Bktero Voir le message
    A quoi sert using value_type = T; ?
    Dans le code de mon précédent message, je l'ai utilisé ici :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    return std::hash<typename StrongTypeT::value_type>()(param.value());
    De manière générale, cela facilite le code de l'utilisateur quand ce dernier fait de la programmation par templates.

    Citation Envoyé par Bktero Voir le message
    Pourquoi le constructeur par référence est-il template ?
    • D'une part, je définis d'un coup le constructeur qui copie le paramètre et le constructeur qui déplace le paramètre, sans que cela ne provoque d'erreur de compilation dans le cas où T est une référence.
      Edit 18h45 : ajout d'une explication : si j'avais écrit :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      	constexpr explicit StrongType(const T& value) : m_value(value)            {}
      	constexpr explicit StrongType(T&& value)      : m_value(std::move(value)) {}
      cela aurait provoqué une erreur de compilation dans le cas où T serait une référence. Par exemple, si T = int&, alors const T& et T&& désignent tous les deux int&, en vertu des reference collapsing rules. Les deux constructeurs ayant la même signature, cela provoque une erreur de compilation.
    • D'autre part, j'accepte tout type U implicitement convertible en T. Par exemple, c'est pratique pour convertir char* en std::string.


    Citation Envoyé par Bktero Voir le message
    L'affectation à T donne t-elle une valeur par défaut au paramètre template (comme pour un paramètre formel de fonction) ?
    Oui. Dans template<class U = T>, T est l'argument par défaut du paramètre U.

    Edit 19h04 : réponse à Astraya :
    Citation Envoyé par Astraya Voir le message
    Pour les entiers pas besoin de chercher compliqué...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    enum class UserCode;
    enum class ConfigCode;
    UserCode u = (UserCode)0;
    ConfigCode c = (ConfigCode)0;
    ConfigCode a = u; // Erreur ici
    UserCode b = c; //Erreur ici
    Bien vu.
    Avec les enum class, lors de l'initialisation, pour éviter de répéter le type, on peut écrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    auto userCode   = UserCode(1);
    auto configCode = ConfigCode(5);
    Par contre, si on veut convertir en int, à la place de value(), on doit passer par un cast :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int userCodeInt = static_cast<int>(userCode);

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

Discussions similaires

  1. Comment faire ma propre classe/template vecteur
    Par touftouf57 dans le forum Visual C++
    Réponses: 2
    Dernier message: 11/11/2010, 12h43
  2. Réponses: 4
    Dernier message: 03/02/2009, 19h47
  3. Réponses: 6
    Dernier message: 10/09/2007, 10h44
  4. Récupérer les noms des classes parents
    Par see++ dans le forum Général Python
    Réponses: 2
    Dernier message: 12/03/2007, 17h35
  5. Vous gerez comment les options d'un programme?
    Par n0n0 dans le forum C++Builder
    Réponses: 5
    Dernier message: 17/05/2002, 13h21

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