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 :

std::enable_if, variadic template et constructeur


Sujet :

C++

  1. #1
    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 std::enable_if, variadic template et constructeur
    Bonjour tout le monde,

    J'ai une petite question dont je n'arrive pas à trouver de réponse sur le net: comment/peut-on utiliser std::enable_if avec les variadic templates pour activer ou non tel constructeur en fonction du nombre de paramètre?

    Voici un petit exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    template<size_t SIZE = 3>
    class Test
    {
       public:
         template<typename... Args>
         Test(typename<std::enable_if<sizeof...(Args) <= SIZE, Args...>::type args) // J'ai essayé différentes syntaxe mais ça ne semble pas fonctionner
         {
          // blabla
         }
    };
    A l'heure actuelle, pour avoir le comportement voulu, j'utilise static_assert:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    template<size_t SIZE = 3>
    class Test
    {
       public:
         template<typename... Args>
         Test(Args... args)
         {
            static_assert(sizeof...(Args) <= SIZE, "Trop d'arguments");
         }
    };
    C'est plus une question pour satisfaire ma curiosité sur tout ce qui tourne autour des variadic template qu'une réelle nécessité.

    Merci d'avance

  2. #2
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    760
    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 : 760
    Par défaut
    Mettre enable_if dans le paramètre template empêche la déduction automatique des types. Et comme on ne peut pas spécifier les types template d'un constructeur, cette solution n'en est pas viable (template variadique ou non).

    Par contre, on peut mettre enable_if autre part:
    - dans le type de retour (oups ) ou
    - dans la liste des paramètres templates: template<class... Args, class = std::enable_if_t<sizeof...(Args) <= SIZE>> Test(Args... args).

  3. #3
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 635
    Par défaut
    Salut,

    De manière générale, il y a deux situations possibles :
    Soit tu veux adapter le comportement du constructeur par rapport au tydpe réel du paramètre template, en gardant le même nombre de paramètres du même type
    Soit tu veux adapter le nombre (et le type éventuellement) des paramètres en fonction du paramètre template.

    Dans le premier cas, il faudra placer std::enable_if dans la liste des paramètres, sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    template <typename T>
    class MyClass{
    public:
        template <typename U =  T>
        MyClass(Type1 p1, Type2 p2, std::enable_if< TestOnU::value>::type * = nullptr){  //(*)
           /* ... */
        }
        template <typename U =  T>
        MyClass(Type1 p1, Type2 p2, std::enable_if< OtherTestOnU::value>::type * = nullptr){ //(*)
           /* ... */
        }
    };
    parce que le nombre et le type des paramètres explicites demandés étant identique , les deux versions ne sont pas considérées comme étant des surcharges valides.

    (*)TestOnU et OtherTestOnU seront sans doute différents type_traits tels que définis dans le fichier <type_traits> (ou des type_traits personnalisés)
    Dans le deuxième cas tu peux placer std::enable_if dans la liste des paramètres template sous une forme qui pourrait être proche de
    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
    template<typename T, size_t SIZE>
    class MathVector{
        using tab_t = std::array<T, SIZE>;
    public:
        /* constructeur par défaut, commun à tous les types concrets */
        MathVector(){
            tab_.fill(T{});
        }
        /* pour un vecteur contenant deux valeurs uniquement */
        template <typename U,
                         std::enable_if<SIZE == 2>::type>
        MathVector(U v1, U v2):MathVector({v1,v2}){
        }
        /* pour un vecteur contenant trois valeurs uniquement */
        template <typename U,
                         std::enable_if<SIZE == 3>::type>
        MathVector(U v1, U v2, U v3):MathVector({v1,v2,v3}){
        }
        /* pour un vecteur contenant quatre valeurs uniquement */
        template <typename U,
                         std::enable_if<SIZE == 4>::type>
        MathVector(U v1, U v2, U v3, U v4):MathVector({v1,v2,v3, v4}){
        }
        MathVector(std::initializer_list const & l):tab_{l}{
        }
        T operator[](size_t index) const{
            assert(index < SIZE);
            return tab_[index],
        }
        T & operator[](size_t index) {
            assert(index < SIZE);
            return tab_[index],
        }
        /* sans doute d'autres trucs sympa, comme les fonctions begin et end, dans différentes versions */
    private:
        tab_t tab_;
    };
    Dans ce cas, le nombre de paramètres attendus par le constructeur variant en fonction de la situation, chaque version est bel et bien à une surcharge valide

    NOTA: j'ai écrit ce code "de mémoire" car j'en ai effectivement mis un semblable en place récemment, mais je ne garanti pas que les tests indiqués soient ceux qui sont effectivement nécessaires (en plus, je m'étais fait des type_traits du genre isVec2, isVec3 et isVec4 pour la facilité )
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  4. #4
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    760
    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 : 760
    Par défaut
    Il faut savoir qu'avec des variadiques, mettre enable_if dans les paramètres de fonction ne fonctionne pas. Le compilateur va ignorer la variadique à cause de la présence de valeur à droite et du coup on se retrouve avec une fonction variadique de taille 0.

  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
    Merci pour toutes vos réponses!

    Je viens de tester avec les std::enable_if et j'obtiens bien le comportement souhaité: à savoir qu'il y ait une erreur de compilation si le nombre d'arguments n'est pas correct. Vu que je ne souhaite pas des comportements différents en fonction de la taille, je pense qu'il est plus sage pour moi d'utiliser les static_assert pour obtenir un message d'erreur plus compréhensible.

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

Discussions similaires

  1. Variadic templates et std::function
    Par white_tentacle dans le forum C++
    Réponses: 36
    Dernier message: 08/07/2014, 10h38
  2. Constructeur variadic template
    Par DakM dans le forum Langage
    Réponses: 5
    Dernier message: 14/07/2013, 02h32
  3. Réponses: 4
    Dernier message: 30/05/2011, 19h38
  4. [C++0x] Variadic template : un constructeur par type
    Par Florian Goo dans le forum Langage
    Réponses: 2
    Dernier message: 08/04/2009, 18h33
  5. classe template pb constructeur
    Par ouinih dans le forum Langage
    Réponses: 6
    Dernier message: 16/08/2007, 18h02

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