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 :

[C++] Template et paramètres optionels


Sujet :

C++

  1. #1
    Membre Expert
    Avatar de Aspic
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    3 905
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2005
    Messages : 3 905
    Par défaut [C++] Template et paramètres optionels
    Bonjour à tous,

    Je me demandais s'il était possible de savoir le nombre de paramètre réellement passé à mon constructeur de classe (sans passé par les va_arg, va_list,... du C) qui a des "template par défaut" :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template <typename T1, typename T2 = void*, typename T3 = void*>
    class MA_CLASSE
    {
    MA_CLASSE(T1 _p1, T2 _p2 = (void*)0, T3 _p3 = (void*)0)
            : p1(_p1),  p2(_p2),  p3(_p3)
    };
     
    // exemples d'appel :
    MA_CLASSE<int> c1; // un seul paramètre fourni
    MA_CLASSE<int, float> c2; // 2 params
    MA_CLASSE<int, flat, int> c3; // 3 paramètres
    Je sais que ce n'est peut être pas très élégant de mettre des "void*" en C++ mais je n'ai pas trouvé d'autre solution pour pouvoir instancier ma classe template avec un ou plusieurs types.

    Voilà, Merci à vous
    Qui ne tente rien n'a rien !
    Ce qui ne nous tue pas nous rends plus fort !!
    Mon projet ZELDA en C++/Allegro
    http://www.tutoworld.com - Le Forum -
    Mes ressources Dotnet (cours, sources, tutos)
    --------------------------------------------
    + + =

    Ne pas oublier le Tag !

  2. #2
    Membre Expert Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Par défaut
    Salut,

    Pour prendre les choses dans l'ordre :

    le nombre de paramètre réellement passé à mon constructeur de classe
    Utiliser l'overload de constructeur au lieu de paramètre par défaut ?

    Si tu peux utiliser le C++11 tu peux considérer les variadic template qui pourraient convenir.

    Sinon il y a un problème dans ton implémentation, quand tu utilises des arguments par défaut dans le constructeur tu leur affectes une valeur, or tu n'es pas sûre que cette valeur soit correcte en fonction du type. Par exemple je peux appeler ta classe comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Ma_classe<int, MonType> m(5);
    Si MonType n'a pas un opérateur d'affectation prenant un (void*) alors tu auras une erreur de compilation.

    Il existe plusieurs solutions pour régler ce genre de problème mais ça dépend vraiment du contexte et de la sémantique de ta classe. Si tu veux un avis qui soit personnalisé, dit nous ce que tu essayes de faire avec ta classe.

  3. #3
    Membre chevronné

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Par défaut
    Est-ce que tu cherches a avoir un tuple (ou avec boost si tu ne peux pas utiliser le c++11) ?

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

    Informations professionnelles :
    Activité : aucun

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

    Si tu peux utiliser C++11, tu aurais presque intérêt à utiliser les variadic template, de manière a avoir un nombre d'argument réellement variable.

    Tu pourrait savoir exactement le nombre d'élément que tu as sous grace à sizeof :
    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
    #include <iostream>
    template <typename ... Args>
    struct MyStruct
    {
        enum {size = sizeof...(Args)};
    };
    using NoArgs = MyStruct<>;
    using OneArg = MyStruct<int>;
    using TwoArgs = MyStruct<int, std::string>;
    int main()
    {
        std::cout<<"NoArgs has "<<NoArgs::size << " arguments"<<std::endl
                 <<"OneArg has "<<OneArg ::size << " arguments"<<std::endl
                 <<"TwoArgs has "<<TwoArgs ::size << " arguments"<<std::endl;
    }
    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

  5. #5
    Membre Expert
    Avatar de Aspic
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    3 905
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2005
    Messages : 3 905
    Par défaut
    Avec l'overload du contructeur, ca marche

    Je viens de me renseigner sur le variadic template, ca a l'air super puissant ce truc (je ne connaissais pas du tout).

    Par contre, comment on fait pour récupérer les types et les valeurs des paramètres vairables ? lol
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    template <typename ... Args>
    struct MyStruct
    {
        enum {size = sizeof...(Args)};
     
        MyStruct()
        {
            std::cout << "comment récupérer mes types ?" << std::endl;
        }
    };
     
    // et son appel :
    MyStruct<int, float> toto(5, 10.5);
    Le but en fait est de créer une classe avec des paramètres génériques variables. Donc si je fais par exemple : Param<int, float, double>, je voudrais créer une classe avec 3 membres int m_1, float m_2, double m_3
    Et si j'appel comme cela : Param<int> alors je n'ai que int m_1

    PS : je n'ai pas trouvé de très bon article sur ce sujet (en français ), celui la est assez incompréhensible :
    http://blog.emmanueldeloget.com/inde...es-variadiques

    PS 2 : Je n'utilise pas Boost.

    Merci
    Qui ne tente rien n'a rien !
    Ce qui ne nous tue pas nous rends plus fort !!
    Mon projet ZELDA en C++/Allegro
    http://www.tutoworld.com - Le Forum -
    Mes ressources Dotnet (cours, sources, tutos)
    --------------------------------------------
    + + =

    Ne pas oublier le Tag !

  6. #6
    Membre chevronné

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Par défaut
    Au risque de répéter un peu ce qui a déjà été dit : pour t'aider plus au delà, il faudrait savoir ce que tu cherches à faire avec cette classe. L'exemple de Koala est joli, mais il ne te montre pas ce qu'il y a de plus dur à faire, c'est à dire justement créer des variables membres selon les types templates.

    Tu as des gens qui ont déjà pris la peine de le faire, par exemple dans le standard c++11 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include <tuple>
    #include <iostream>
     
    int main() {
        std::tuple<int, float> toto(5, 10.5);
        std::cout << "premiere valeur : " << std::get<0>(toto) << std::endl;
        std::cout << "seconde valeur  : " << std::get<1>(toto) << std::endl;
        return 0;
    }
    Plusieurs questions donc :
    • est-ce que toutes tes instances de MaClasse doivent avoir 3 variables membres, et tu veux juste pouvoir n'en initialiser que quelques unes ?
    • dans le cas contraire, est-ce que tu auras toujours 3 types au maximum, ou est-ce que ça peut changer ?
    • et est-ce que tu vas toujours utiliser MaClasse avec de types fixes (ex : int, float, int), ou est-ce que ça peut changer ?
    • à quoi ça sert ?

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 641
    Par défaut
    Tiens, l'article d'emmanuel est celui qui m'a permis de comprendre le principe des variadic template

    Mais, de manière générale, il est vrai que l'on arrive très rapidement à un niveau de complexité qui nécessite une maitrise très correcte du paradigme générique si on veut les utiliser correctement

    Parce que, pour faire simple, on pourrait dire que la gestion des arguments passés sous la forme d'une liste de template variadiques nécessite l'appel à la récursivité (mais je te rassure, à la récursivité "compile time" )

    Je vais, si tu veux bien, et au risque de parler de quelque chose que tu connais déjà, commencer par parler de la récursivité dans les template "classiques".

    Tu as sans doute déjà aperçu l'article qui parle de la meta programmation et qui indique comment utiliser la spécialisation partielle des template pour calculer, une factorielle, par exemple

    Si ce n'est pas le cas, et pour t'éviter d'avoir à relire l'article au grand complet (quoi que je ne peux que t'inciter à le faire quand meme ),
    il faut savoir que le compilateur est capable de "dérouler des boucle" lorsqu'on lui passe des expressions constantes, et surtout dans le cadre de l'utilisation de template.

    Ainsi, nous pourrions très bien demander au compilateur de nous générer une constante de compilation représentant la factorielle d'un nombre avec un code qui utilise la spécialisation partielle (totale, dans le cas présent) et qui serait 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
    /* de manière générale, la factorielle d'un nombre est égale à la multiplication
     * de ce nombre par la factorielle du nombre -1
     */
    template <int Value>
    struct Farctorielle
    {
        enum {value = Value * Factorielle<Value-1>::value};
    };
    /* mais il faut bien arrêter la récursion à un moment donné...
     * cela se fait quand on arrive à 0, et la factorielle de 0 donne 1
     * (c'est le "cas de base" qu'il faut essayer de gérer comme dans
     * toute fonction récursive ;) )
     */
    template
    struct Factorielle<0> //spécialisation totale de Factorielle
    {
       enum {value = 1};
    };
    Ainsi, lorsque l'on écrira un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int main()
    {
       int fact5 = Factorielle<5>::value;
    }
    le compilateur réagira 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
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    int fact5 = 5 * Factorielle<4>::value;
    /* mince, je dois calculer la factorielle de 4 */
    int temp4 = 4 * Factorielle<3>::value;
    /* mince, je dois calculer la factorielle de 3 */
    int temp3 = 3 * Factorielle<2>::value;
    /* mince, je dois calculer la factorielle de 2 */
    int temp2 = 2 * Factorielle<1>::value;
    /* mince, je dois calculer la factorielle de 1 */
    int temp1 = 1 * Factorielle<0>::value;
    /* mince, je dois calculer la factorielle de 0
     * Mais ca, c'est facile... value = 1 */
    int temp0 = 1;
    /* donc temp1 = 1*1 */
    temp1 = 1;
    /* donc temp2 = 2*1 */
    temp2 = 2;
    /* donc temp3 = 3*2 */
    temp3 = 6;
    /* donc temp4 = 4*6 */
    temp4 = 24
    /* donc fact5 = 5*24 */
    fact5 = 120
    Et, comme il aura suivi tout ce raisonnement au moment de la compilation, il remplacera directement dans le code de main tous ces appels à Factorielle par... la valeur du résultat, et cela reviendra exactement au même que si on avait écrit
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int main()
    {
       int fact5 = 120;
    }
    Une fois que tu as compris cela, le reste devrait finalement être beaucoup plus facile à comprendre

    La deuxième chose dont il faut se souvenir (parce qu'on l'utilise sans arrêt, et je considère donc que tu le sais ), c'est que C++ autorise la surcharge de fonctions.

    Une surcharge de fonction peut prendre deux formes:
    • lorsque le prototype de la fonction accepte le même nombre d'arguments, mais il y a au minimum un argument dont le type est différent ou
    • si le prototype de la fonction accepte un nombre différent d'arguments

    Le premier cas s'applique, par exemple sur les fonctions
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    void foo(int );
    void foo(std::string const &);
    et le deuxième cas s'applique sur les fonctions
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    void foo(int);
    void foo(int, int );
    void foo(int, int, int);
    et donc, il y aura fatalement surcharge avec les fonctions
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    void foo(int); // (1)
    void foo(std::string const &); //(2) différent de (1) par le type de l'argument
    void foo(int, int); //(3) différent de (1) par le nombre d'arguments
    void foo(std::string const &, int) //(4) différent de (2) par le nombre d'arguments et 
                                       // différent de (3) parce que le premier argument est de type différent
    La norme nous dit que, lorsque l'on utilise les variadic template, l'ensemble des types et des valeurs associées qui entre dans le cadre de l'élipse ( les fameux ... ) s'appelle un paramter package.
    A défaut de mieux, nous pouvons sans doute traduire cela par un paquet de paramètres (en fait, je ne sais pas si la communauté francophone a déjà trouvé un concensus quant à la traduction de ce terme )

    Et la norme nous dit que le paquet de paramètres va contenir "tout ce qui n'entre pas dans le nombre et le type des arguments explicites".

    Cela signifie que si tu as une fonction qui ne prend qu'un paquet de paramètres, sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template <typename ... Args>
    void foo( Args ... args);
    et que tu l'appelle sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    foo<int, int, int, int>(1, 2, 3, 4);
    le paquet d'arguments sera composé de quatre int dont les valeurs respectives sont 1, 2, 3 et 4.

    Par contre, si tu surcharge la fonction sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template <int, typename ... Args>
    void foo(int one, Args ... args);
    comme le compilateur est de nature paresseuse, il choisira la surcharge de la fonction qui lui demande le moins de travail avec le même code.

    Ainsi, si tu donnes les deux prototypes de fonction au compilateur et que tu écris le code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    foo<int, int, int, int>(1, 2, 3, 4);
    (qui n'a pas changé depuis la tantot ), comme cela demande moins de boulot au compilateur de créer un paquet de paramètres contenant trois paires Type / Valeur que d'en créer un qui contient quatre paire Type / Valeur, il choisira d'office d'appeler foo(int, Args... args) (on parle en anglais du best match : ce qui correspond le mieux à ce qui est demandé )

    Mais, pour l'instant, je n'ai pas encore donner de corps à mes différentes surcharges de foo...

    Et c'est là que la récursivité entre en jeu

    En effet, si j'implémente la surcharge de foo qui prend dés le départ un int sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    template <typename Args...args>
    void foo(int i, Args...args>
    {
        std::cout<<i<<std::endl; // j'utilise i
        foo(...args); // je rentre dans la récursivité
    }
    mon code de la tantot va être résolu sous une forme proche de
    appeler foo(int i, Args ... args) avec i = 1 et args = 2, 3, 4
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    utiliser i
    appeler foo(int i, Args ... args) avec i = 2 et args = 3,4
    utiliser i
    appeler foo(int i, Args ... args) avec i = 3 et args = 4
    utiliser i
    appeler foo(int i, Args ... args) avec i = 4 et args = rien du tout
    utiliser i
    appeler foo... oups, avec rien du tout 
    ==> foo(Args...args) fait l'affaire ;)
    Enfin, cela fera l'affaire tant que je profite de l'appel à cette fonction pour arrêter la récursivité avec l'implémentation sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template<typename...Args>
    void foo(Args... args)
    {
        std::cout<<"stopping with "<<sizeof...(args)<< " unused arguments"<<std::endl;
    }
    Seulement, voilà, j'ai, certes, appelé foo avec un nombre d'argument variable, mais tous les arguments étaient du même type

    Or, je peux faire varier le nombre des arguments, mais aussi leur type !!!

    Je pourrais très bien décider d'écrire un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int main()
    {
     
        foo<int, int,int, int, std::string const &, int, int >(1, 2, 3, 4,5 ,
                                                       "salut", 6, 7 );
        return 0;
    }
    Et là, bien que cela compile sans problème, l'exécution va m'apporter une lourde déception...

    Car, en effet, j'aurais un résultat proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    using i = 1, left 7 argument more
    using i = 2, left 6 argument more
    using i = 3, left 5 argument more
    using i = 4, left 4 argument more
    using i = 5, left 3 argument more
    stopping with 3 unused arguments
    Mais bon, c'est normal...

    Car après avoir utilisés les argument 1, 2, 3, 4 et 5, le compilateur se trouve dans une situation où le seul prototype qui convient pour gérer "salut",6,7 ben... c'est le prototype tout à fait générique

    Au moment d'appeler foo("salut",6, 7 ) il va donc appler... foo(Args...args)

    Mais bon, je présumes que tu auras trouvé par toi même la parade, non

    Allez, je vais me faire un café, et je te laisse ce temps là pour y réfléchir

    Alors, tu as très certainement trouvé la solution, hein

    Mais oui, mais c'est bien sur : ajoutons donc une surcharge à foo qui prend une std::string comme argument

    Sitôt dit, sitôt fait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    template<typename ... Args>
    void foo(std::string const & s, Args...args)
    {
        std::cout<<"using the "<<s<<" string, left "
                 <<sizeof...(args)<<" argument more"<<std::endl;
        foo(args...);
    }
    Et, "normalement", ca marche...

    Note que je vais devoir me renseigner, car il y a peut etre un bug au niveau de gcc dans le sens où, si j'écris le code sous la forme 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
    template<typename ...Args>
    void foo(Args ... args)
    {
        std::cout<<"stopping with "<<sizeof...(args)<< " unused arguments"<<std::endl;
    }
    template<typename ...Args>
    void foo(int i, Args ... args)
    {
        std::cout<<"using i = "<<i
                 <<", left "<<sizeof...(args)<<" argument more"<<std::endl;
        foo(args...);
    }
    template<typename ... Args>
    void foo(std::string const & s, Args...args)
    {
        std::cout<<"using the "<<s<<" string, left "
                 <<sizeof...(args)<<" argument more"<<std::endl;
        foo(args...);
    }
    int main()
    {
     
        foo<int, int,int, int, std::string , int, int >(1, 2, 3, 4,5 ,
                                                       "salut", 6, 7 );
        return 0;
    }
    l'exécution s'arrete arpès avoir utilisé 5, alors que si je l'écris sous la forme 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
    template<typename ...Args>
    void foo(int i, Args ... args);
    template<typename ...Args>
    void foo(std::string const & s, Args...args);
    template<typename ...Args>
    void foo(Args ... args)
    {
        std::cout<<"stopping with "<<sizeof...(args)<< " unused arguments"<<std::endl;
    }
    template<typename ... Args>
    void foo(std::string const & s, Args...args)
    {
        std::cout<<"using the "<<s<<" string, left "
                 <<sizeof...(args)<<" argument more"<<std::endl;
        foo(args...);
    }
    template<typename ...Args>
    void foo(int i, Args ... args)
    {
        std::cout<<"using i = "<<i
                 <<", left "<<sizeof...(args)<<" argument more"<<std::endl;
        foo(args...);
    }
    int main()
    {
     
        foo<int, int,int, int, std::string , int, int >(1, 2, 3, 4,5 ,
                                                       "salut", 6, 7 );
        return 0;
    }
    cela fonctionne correctement

    Enfin bon, en attendant, ceci n'est sans doute qu'un détail (ceux qui ont un avis sur la question peuvent y répondre ici )

    Il nous reste un dernier cas qu'il est intéressant d'envisager...

    C'est bien sur celui qui te permet de gérer "n'importe quel type d'argument", pour autant que tu saches comment tu va le gérer

    Hé bien, tu pourrais aussi généraliser le type du premier argument, en partant, par exemple, du principe qu'il existe une surcharge de l'opérateur << pour le type d'argument que tu voudras passer

    La surcharge de foo pourrait alors ressembler à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    template <typename T, typename ... Args>
    void foo(T const & t, Args ... args)
    {
        std::cout<<"using a generic type "<<t
                 <<", left "<<sizeof...(args)<<" argument more"<<std::endl;
        foo(args...);
    }
    Alors, bien sur, il y a encore beaucoup à dire, mais je crois que je t'ai déjà donné une explication qui t'aidera à bien avancer

    Ce qui importe, c'est de penser non seulement à la surcharge de fonction, mais aussi à la récursivité (en n'oubliant pas de vérifier le cas de base, à savoir "yapu d'arguments" ) et en n'oubliant pas que tu peux savoir exactement le nombre d'arguments qui se trouve dans le paquet d'arguments en utilisant la syntaxe sizeof ... (nom du paquet)
    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

  8. #8
    Membre Expert
    Avatar de Aspic
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    3 905
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2005
    Messages : 3 905
    Par défaut
    Salut,

    Merci beaucoup pour ton explication !
    Très claire et bien détaillée
    Je vais prendre le temps de découvrir ce nouveau paradigme quand j'aurais un peu de temps.

    Qui ne tente rien n'a rien !
    Ce qui ne nous tue pas nous rends plus fort !!
    Mon projet ZELDA en C++/Allegro
    http://www.tutoworld.com - Le Forum -
    Mes ressources Dotnet (cours, sources, tutos)
    --------------------------------------------
    + + =

    Ne pas oublier le Tag !

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

Discussions similaires

  1. Trier dans un template avec paramètres
    Par stujava dans le forum XSL/XSLT/XPATH
    Réponses: 4
    Dernier message: 23/02/2010, 08h03
  2. Requêtes avec paramètres optionels + TMC
    Par cfeltz dans le forum MS SQL Server
    Réponses: 5
    Dernier message: 23/08/2007, 11h30
  3. Réponses: 15
    Dernier message: 21/08/2006, 01h41
  4. [XSL]Valeur d'un call-template en paramètre with-param
    Par camboui dans le forum XSL/XSLT/XPATH
    Réponses: 5
    Dernier message: 20/03/2006, 14h45
  5. [VB6]Question bête sur les paramètres optionels
    Par méphistopheles dans le forum VB 6 et antérieur
    Réponses: 2
    Dernier message: 17/10/2005, 20h33

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