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

Langage C++ Discussion :

typedef et variadic template


Sujet :

Langage C++

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    199
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 199
    Par défaut typedef et variadic template
    Bonjour!

    Ma question peut semblait bete mais pourquoi la nouvelle norme n'a pas introduit le typedef sur les variadics templates.

    En effet par exemple avec std::function je peux retrouver le type de la valeur de retour mais pas ceux des arguments et donc je dois les trimballer en tant que parametres template.

    Merci!

  2. #2
    Membre Expert

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Par défaut
    Bonjour,

    Quel serait le sens d'un "typedef sur variadic template" ?
    Tu as un exemple de ce que pourrait être un tel typedef ?

  3. #3
    Membre Expert

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Par défaut
    Citation Envoyé par victor_gasgas Voir le message
    En effet par exemple avec std::function je peux retrouver le type de la valeur de retour mais pas ceux des arguments et donc je dois les trimballer en tant que parametres template.
    Utilises boost::function, tu pourras les récupérer. Le comité a peut-être jugé que ce n'était utile que pour les foncteurs unaires et binaires (où là tu peux récupérer les types des arguments).

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    199
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 199
    Par défaut
    J'utilise une fonction récursive template qui se trimballe une std::function et au cas d'arrêt de la récursion j'ai besoin d’appeler la std::function et donc de retrouver les types de paramètres.
    Donc je me garde les arguments en paramètre template tout le long..

    Merci je vais me pencher sur boost sinon je garde ma méthode actuelle.

    Par contre Flob90 j'ai trouvé ce code dont vous semblez être l'auteur:
    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
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    #include <iostream>
    #include <vector>
    #include <functional>
     
    using namespace std;
     
    template<typename T>
    class Signal;
     
    template<typename R, typename... Args>
    class Signal<R(Args...)>
    {
        typedef function<R(Args...)> F;
    public:
        template<class T>
        void Connect(T&& Callback)
        {
            MyCallbacks.push_back(Callback);
        }
        vector<R> operator()(Args&&... args) const
        {
            vector<R> results;
            for(F const& f : MyCallbacks)
                results.push_back(f(std::forward<Args>(args)...));
     
            return results;
        }
     
    private:
        vector<F> MyCallbacks;
    };
    template<typename... Args>
    class Signal<void(Args...)>
    {
        typedef function<void(Args...)> F;
    public:
        template<class R>
        void Connect(R&& Callback)
        {
            MyCallbacks.push_back(Callback);
        }
        void operator()(Args&&... args) const
        {
            for(F const& f : MyCallbacks)
                    f(std::forward<Args>(args)...);
        }
    private:
        vector<F> MyCallbacks;
    };
     
    void DisplayString(std::string const& str)
    {
        std::cout << "Displayed: " << str << std::endl;
    }
     
    int main()
    {
        Signal<void (std::string const&)> Out;
     
        Out.Connect(DisplayString);
        Out("Bonjour tout le monde !");
     
        return 0;
    }
    Il y est donnée une explication sur les && et std::forward mais j'ai du mal à saisir l'intêret. Comment cela évite-t-il les copie.

    Si quelqu'un peut me l'expliquer. Merci beaucoup

  5. #5
    Membre Expert

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Par défaut
    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
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
     
    #include<iostream>
    #include<functional>
    #include<utility>
    #include<vector>
     
    template<class T>
    struct Sig;
     
    template<class... Arg>
    class Sig<void(Arg...)>
    {
    	typedef std::function<void(Arg...)> F;
    	std::vector<F> _v;
     
    public:
    	template<class T>
    	void connect(T&& f)
    	{ _v.push_back(std::forward<T>(f)); }
               template<class... Arg2>
    	void operator()(Arg2&&... arg) const
    	{
    		for(const F& f : _v)
    			f(std::forward<Arg2>(arg)...);
    	}
    };
     
    struct A
    {
    	A(){ std::cout << " A-ctor "; }
    	~A(){ std::cout << " A-dtor "; }
    	A(const A&){ std::cout << " A-copy-ctor "; }
    	A(A&&){ std::cout << " A-move "; }
    };
     
    struct Func
    {
    	Func(){ std::cout << " Func-ctor "; }
    	~Func(){ std::cout << " Func-dtor "; }
    	Func(const Func&){ std::cout << " Func-copy-ctor "; }
    	Func(Func&&){ std::cout << " Func-move "; }
    	void operator()(A) const
    	{ std::cout << " 1 "; }
    };
     
     
    int main()
    {
    	Sig<void(A)> s;
    	s.connect(Func());
    	s(A());
    }
    Si tu observes la sortie de ce code tu verras qu'il y a appel aux move-ctor et pas aux copy-ctor.

    Mon exemple n'est pas très parlant sur la différence entre un copy-ctor et un move-ctor, pour détailler un peu, la syntaxe A(A&& p) nous indique un constructeur prenant en paramètre un rref sur un A qui indique que ce A est sur le point d'être détruit et qu'on peut donc récupérer ses ressources, évitant ainsi de les copier. Par exempe (sans rapport avec le code d'avant) :
    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
     
    struct A_impl
    { 
    	/*complexe data with copy-ctor*/ 
    	A_impl() { std::cout << " ctor "; }
    	A_impl(const A_impl&) { std::cout << " copy-ctor "; }
    };
     
    struct OldA
    {
    	A_impl* p;
    	OldA() : p(new A_impl()) {}
    	OldA(const OldA& a) : p(new A_impl(*a.p)) {}
    	~OldA() { delete p; }
    };
     
    struct NewA
    {
    	A_impl* p;
    	NewA() : p(new A_impl()) {}
    	NewA(const NewA& a) : p(new A_impl(*a.p)) {}
    	NewA(NewA&& a) : p(a.p) {}
    	~NewA() { delete p; }
    };
    Là tu peux voir que quand le move-ctor est utilisé il n'y a pas de copie de l'implémentation de A (Impl_A) ce qui peut se révéler coûteux. Reinjectes OldA ou NewA dans le code précédent (à la place de A) tu verras que dans un cas il y aura écrit copy-ctor (plusieurs fois) et dans l'autre il n'y aura aucune copie.

    NB: Le code donné pour Sig au début est un "morceaux" de l'autre (j'utilise pas l'autre partie dans l'exemple) et j'ai corrigé un oublie.

    NB2: Je manipule les pointeurs nue dans l'exemple (pour OldA, NewA) utiliser std::unique_ptr + std::move serait une meilleur idée (mais tu risquais de ne pas voir cette utilité des rref si je les utilisais).

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    199
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 199
    Par défaut
    D'accord déjà je comprends mieux.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    // Code 1
    template<typename... Args>
    void foo(Args... args)   { /* Some code */ }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    // Code 2
    template<typename... Args>
    void foo(Args&&... args)   { /* Some code */ }
    a- Par contre est-ce le compilo qui fait le choix entre un appel normal et un appel avec rref ? Et il prends le second que si le paramètre n'est qu'un temporaire? (Cela implique un move-contructor, mais s'il est non définit explicitement c'est bien le compilo qui s'en occupe non, de la même façon que le destructeur ou copy-constructor).

    b- L'utilisation de std::forward() permet de "sortir" le &&. Je sais c'est expliquer avec les mains sur le coup là!

    c- Dans le code ci-dessus toujours privilégié le code 2 utilisé conjointement avec std::forward()? Où on à des contres exemples et/ou restriction d'usage?


    Merci beaucoup encore de l’intérêt porté!

  7. #7
    Membre Expert

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Par défaut
    a/ Oui, le compilo choisie, il regarde quel genre de paramètre du lui donne, une rvalue ou une lvalue, et selon ce que c'est il appel la fonction prenant en argument une lvalue ou une rvalue.

    Pour la définition automatique du move-ctor, oui c'est automatiquement définient de la même manière que le copy-ctor, avec le même genre de règles.

    b/ Non, il permet de "faire suivre" la ressource : passer une rref si c'est une rref, une lref si c'est une lref. Tests 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
     
    #include<iostream>
    #include<utility>
     
    struct A
    {
    	A() {}
    	A(const A&) { std::cout << " copy-ctor "; }
    	A(A&&) { std::cout << " move-ctor "; }
    };
     
    void bar(A&&)
    { std::cout << " bar-rref "; }
     
    void bar(A&)
    { std::cout << " bar-lref "; }
     
    void foo_1(A&& a)
    { bar(a); }
     
    void foo_2(A&& a)
    { bar(std::forward<A>(a)); }
     
    int main()
    {
    	foo_1(A()); //bar-lref
    	foo_2(A()); //bar-rref
    }
    c/ Le comportement des rref avec les templates est un peu spécifique, elle va récupèrer aussi bien les lvalue que les rvalue, T étant "évalué" à T& (et donc (T&)&& = T&) si c'est une lvalue, et à T si c'est un rvalue.

    En lecture sur le sujet il y a une série d'article à propos de la move-semantic sur C++Next.

  8. #8
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    199
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 199
    Par défaut
    Ok je viens de tester ton exemple et ça éclaircie déjà pas mal!

    La seule question qui me reste est de savoir s'il y à des précautions à avoir avec les rvalue et std::forward()?

    Par contre je connais pas du tout C++Next, j'y vais de ce pas!

Discussions similaires

  1. Réponses: 2
    Dernier message: 10/01/2009, 13h38
  2. [C++] typedef dans des template
    Par inh40 dans le forum Langage
    Réponses: 1
    Dernier message: 10/12/2007, 17h59
  3. Typedef sur fonction template
    Par mchk0123 dans le forum Langage
    Réponses: 7
    Dernier message: 01/04/2007, 15h07
  4. Réponses: 5
    Dernier message: 17/06/2005, 19h26

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