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 :

specialisation des templates variadic


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre habitué
    Inscrit en
    Février 2010
    Messages
    11
    Détails du profil
    Informations forums :
    Inscription : Février 2010
    Messages : 11
    Par défaut specialisation des templates variadic
    Bonjour,

    Voici un problème avec les templates variadic.
    En fait, voici les functions disponibles :
    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
     
    template< class ClassType >
    		vector< ClassType * > Clone( const vector< ClassType * > &objects ) const;
     
    		template< class ReturnType >
    		shared_ptr< ReturnType > Get( ReturnType * ( PL::ConcreteAssetFactory::*createFunction )() const , shared_ptr<ReturnType> ( PL::AssetFactoryStore::*getFunction )() const , void ( PL::AssetFactoryStore::*setFunction )( shared_ptr<ReturnType> ) ) const;
     
    		template< class ReturnType , typename Argument >
    		shared_ptr< ReturnType > Get( ReturnType * ( PL::ConcreteAssetFactory::*createFunction )( Argument ) const , shared_ptr<ReturnType>( PL::AssetFactoryStore::*getFunction )( Argument ) const , void ( PL::AssetFactoryStore::*setFunction )( Argument , shared_ptr<ReturnType> ) , Argument arg ) const;
     
    		template< class ReturnType , typename Argument1 , typename Argument2 >
    		shared_ptr< ReturnType > Get( ReturnType * ( PL::ConcreteAssetFactory::*createFunction )( Argument1 , Argument2 ) const , shared_ptr<ReturnType>( PL::AssetFactoryStore::*getFunction )( Argument1 , Argument2 ) const , void ( PL::AssetFactoryStore::*setFunction )( Argument1 , Argument2 , shared_ptr<ReturnType> ) , Argument1 arg1 , Argument2 arg2 ) const;
     
    		template< class ReturnType , typename Argument1 , typename Argument2 >
    		shared_ptr< ReturnType > Get( ReturnType * ( PL::ConcreteAssetFactory::*createFunction )( Argument1 , Argument2 , DateFunctionFactory * ) const , shared_ptr<ReturnType>( PL::AssetFactoryStore::*getFunction )( Argument1 , Argument2 ) const , void ( PL::AssetFactoryStore::*setFunction )( Argument1 , Argument2 , shared_ptr<ReturnType> ) , Argument1 arg1 , Argument2 arg2 , DateFunctionFactory *forwards ) const;
     
    		template< class ReturnType , typename Argument1 , typename Argument2 >
    		shared_ptr< ReturnType > Get( ReturnType * ( PL::ConcreteAssetFactory::*createFunction )( Argument1 , Argument2 , DateFunctionFactory * , DatePairFunctionFactory * ) const , shared_ptr<ReturnType>( PL::AssetFactoryStore::*getFunction )( Argument1 , Argument2 ) const , void ( PL::AssetFactoryStore::*setFunction )( Argument1 , Argument2 , shared_ptr<ReturnType> ) , Argument1 arg1 , Argument2 arg2 , DateFunctionFactory *forwards , DatePairFunctionFactory *drifts ) const;
     
    		template< class ReturnType , typename Argument1 , typename Argument2 >
    		shared_ptr< ReturnType > Get2( ReturnType * ( PL::ConcreteAssetFactory::*createFunction )( Argument1 , Argument2 , DateFunctionFactory * , DateFunctionFactory * ) const , shared_ptr<ReturnType>( PL::AssetFactoryStore::*getFunction )( Argument1 , Argument2 ) const , void ( PL::AssetFactoryStore::*setFunction )( Argument1 , Argument2 , shared_ptr<ReturnType> ) , Argument1 arg1 , Argument2 arg2 , DateFunctionFactory *forwards , DateFunctionFactory *forwardsWithoutDD ) const;
     
    		template< class ReturnType , typename Argument1 , typename Argument2 , typename Argument3 >
    		shared_ptr< ReturnType > Get( ReturnType * ( PL::ConcreteAssetFactory::*createFunction )( Argument1 , Argument2 , Argument3 ) const , shared_ptr<ReturnType>( PL::AssetFactoryStore::*getFunction )( Argument1 , Argument2 , Argument3 ) const , void ( PL::AssetFactoryStore::*setFunction )( Argument1 , Argument2 , Argument3 , shared_ptr<ReturnType> ) , Argument1 arg1 , Argument2 arg2 , Argument3 arg3 ) const;
     
    		template< class ReturnType , typename Argument1 , typename Argument2 , typename Argument3 >
    		shared_ptr< ReturnType > Get( ReturnType * ( PL::ConcreteAssetFactory::*createFunction )( Argument1 , Argument2 , Argument3 , DateFunctionFactory * ) const , shared_ptr<ReturnType>( PL::AssetFactoryStore::*getFunction )( Argument1 , Argument2 , Argument3 ) const , void ( PL::AssetFactoryStore::*setFunction )( Argument1 , Argument2 , Argument3 , shared_ptr<ReturnType> ) , Argument1 arg1 , Argument2 arg2 , Argument3 arg3 , DateFunctionFactory *forwards ) const;

    Comme vous pouvez voir, il y a beaucoup de repetitions venant de différents cas. Je souhaiterais remplacer cela par des templates variadic mais je n'arrive pas à specialiser correctement pour tenir compte des cas où (notamment)
    class T, class ... arg
    Class T, class ... arg, class T2


    Une idée ?

    Merci d'avance.

    Matthieu

  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
    Si tu laisse la fonction déduire les types pour f(Args..., T), alors Args contiendra tous les types et T n'aura jamais de correspondance. Il faut mettre Args dans un contexte différent pour ensuite obtenir T.

    Je te propose un code simplifié que tu pourras adapter à ton cas:
    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>
     
    struct A {
      void foo(int,int){}
      void bar(int){}
    };
     
    #define UNPACK(...) std::initializer_list<int>{(void(__VA_ARGS__),1)...}
     
    template<class... Args>
    struct caller
    {
      template<class... ExtraArgs>
      static void impl(Args & ... args, ExtraArgs & ... extra_args) {
        std::cout << "args:"; UNPACK(std::cout << ' ' << args); std::cout << '\n';
        std::cout << "extra:"; UNPACK(std::cout << ' ' << extra_args); std::cout << '\n';
      }
    };
     
    template<class... Args1, class... Args2>
    void f(void (A::*)(Args1...), void (A::*)(Args2...), Args1 && ... args) {
      caller<Args2...>::impl(args...);
    }
     
    int main() {
      f(&A::foo, &A::foo, 1, 2);
      f(&A::foo, &A::bar, 1, 2);
    }
    args: 1 2
    extra:
    args: 1
    extra: 2

  3. #3
    Membre habitué
    Inscrit en
    Février 2010
    Messages
    11
    Détails du profil
    Informations forums :
    Inscription : Février 2010
    Messages : 11
    Par défaut
    Salut,

    Tout d'abord merci pour ta réponse.
    Ensuite, j'ai tourné le code mais en pratique, je ne comprends pas comment il fait vraiment le lien entre les composants. As-tu une doc lié à cet exemple ou plus de details ?

    Merci d'avance.
    Matthieu


    Citation Envoyé par jo_link_noir Voir le message
    Si tu laisse la fonction déduire les types pour f(Args..., T), alors Args contiendra tous les types et T n'aura jamais de correspondance. Il faut mettre Args dans un contexte différent pour ensuite obtenir T.

    Je te propose un code simplifié que tu pourras adapter à ton cas:
    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>
     
    struct A {
      void foo(int,int){}
      void bar(int){}
    };
     
    #define UNPACK(...) std::initializer_list<int>{(void(__VA_ARGS__),1)...}
     
    template<class... Args>
    struct caller
    {
      template<class... ExtraArgs>
      static void impl(Args & ... args, ExtraArgs & ... extra_args) {
        std::cout << "args:"; UNPACK(std::cout << ' ' << args); std::cout << '\n';
        std::cout << "extra:"; UNPACK(std::cout << ' ' << extra_args); std::cout << '\n';
      }
    };
     
    template<class... Args1, class... Args2>
    void f(void (A::*)(Args1...), void (A::*)(Args2...), Args1 && ... args) {
      caller<Args2...>::impl(args...);
    }
     
    int main() {
      f(&A::foo, &A::foo, 1, 2);
      f(&A::foo, &A::bar, 1, 2);
    }

  4. #4
    Membre Expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2013
    Messages
    610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Avril 2013
    Messages : 610
    Billets dans le blog
    21
    Par défaut
    Ce que dit jo_link_noir, c'est que tu ne peux pas avoir une fonction template de type:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template <typename A, typename... B, typename C>
    void foo(A, B..., C);
    Hélas, même le site de la référence (http://en.cppreference.com/w/cpp/lan...parameter_pack) n'est pas complet sur le sujet: "This section is incomplete. Reason: mention that it must be last in class template, but not function" (ce qui n'est que partiellement vrai.
    J'ai testé cette définition:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template <typename A, typename... B, typename C>
    void foo(A, B..., C);
    avec le dernier gcc, il accepte bizarrement une instantiation avec deux arguments, mais pas trois ou quatre.

    Donc l'idée de jo_link_noir est de capturer les paramètres template à deux endroits différents: dans une struct et dans une fonction membre de la struct.

    Une autre piste sinon, avec using:

    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    template <typename ReturnType, typename... Args>
    using ptrCAFfn = ReturnType* ( PL::ConcreteAssetFactory::*)(Args...) const;
    template <typename ReturnType, typename... Args>
    using sptrCAFfn = shared_ptr<ReturnType>( PL::AssetFactoryStore::*)( Args... ) const;
    template <typename ReturnType, typename... Args>
    using vAFSfn = void ( PL::AssetFactoryStore::*)( Args... , shared_ptr<ReturnType> ) const;

    D'où:
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    template< class ReturnType, typename... Args >
    shared_ptr< ReturnType > Get(ptrCAFfn<ReturnType, Args...>,  sptrCAFfn<ReturnType, Args...>, vAFSfbFfn<ReturnType, Args...>,  Args...) const;

    J'ai testé la partie directive using qui est acceptée par le compilateur. Après je ne sais pas ce que donnerait la déduction de type pour get.

  5. #5
    Membre habitué
    Inscrit en
    Février 2010
    Messages
    11
    Détails du profil
    Informations forums :
    Inscription : Février 2010
    Messages : 11
    Par défaut
    Bonjour,

    Merci pour ce retour. J'ai réussi à mieux apprehender la syntaxe mais j'ai encore un soucis de fusion d'arguments variadic.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
     
     
    virtual ScenarioDateFunction * GetOldOldTodayFunction() const { return new SmartScenarioDateFunction( Get( &PL::ConcreteAssetFactory::CreateOldOldTodayFunction , &PL::AssetFactoryStore::GetOldOldTodayFunction , &PL::AssetFactoryStore::SetOldOldTodayFunction ) ); }
     
     
     
    template< class ReturnType, typename... ArgumentsCreateFunctionComplementary, typename... ArgumentsStoreValues>
    		shared_ptr< ReturnType > Get(ReturnType * (PL::ConcreteAssetFactory::*createFunction)(ArgumentsStoreValues... ,ArgumentsCreateFunctionComplementary...) const, shared_ptr<ReturnType>(PL::AssetFactoryStore::*getFunction)(ArgumentsStoreValues...) const, void (PL::AssetFactoryStore::*setFunction)(ArgumentsStoreValues..., shared_ptr<ReturnType>), ArgumentsStoreValues... arg1, ArgumentsCreateFunctionComplementary...  arg2) const;
    J'obtiens l'erreur suivante qui indique la mauvaise fusion. J'ai trouvé sur internet des méthodes plus complexes mais je ne peux pas les appliquer pour permettre d'utiliser l'interface actuelle et de déduire automatiquement la function template. Une idée ?

    Error 1 error C2780: 'std::shared_ptr<_Ty> PL::ConcreteAssetFactory::Get(ReturnType *(__thiscall PL::ConcreteAssetFactory::* )(ArgumentsStoreValues...,ArgumentsCreateFunctionComplementary...) const,std::shared_ptr<_Ty> (__thiscall PL::AssetFactoryStore::* )(ArgumentsStoreValues...) const,void (__thiscall PL::AssetFactoryStore::* )(ArgumentsStoreValues...,std::shared_ptr<_Ty>),ArgumentsStoreValues...,ArgumentsCreateFunctionComplementary...) const' : expects 5 arguments - 3 provided (ConcreteUnderlyingGridCalculator.cpp) D:\test\Ing Model Library.V3\Inc\PricerLibrary\ConcreteAssetFactory.h 57



    Bien à vous,

    Matthieu


    Citation Envoyé par stendhal666 Voir le message
    Ce que dit jo_link_noir, c'est que tu ne peux pas avoir une fonction template de type:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template <typename A, typename... B, typename C>
    void foo(A, B..., C);
    Hélas, même le site de la référence (http://en.cppreference.com/w/cpp/lan...parameter_pack) n'est pas complet sur le sujet: "This section is incomplete. Reason: mention that it must be last in class template, but not function" (ce qui n'est que partiellement vrai.
    J'ai testé cette définition:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template <typename A, typename... B, typename C>
    void foo(A, B..., C);
    avec le dernier gcc, il accepte bizarrement une instantiation avec deux arguments, mais pas trois ou quatre.

    Donc l'idée de jo_link_noir est de capturer les paramètres template à deux endroits différents: dans une struct et dans une fonction membre de la struct.

    Une autre piste sinon, avec using:

    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    template <typename ReturnType, typename... Args>
    using ptrCAFfn = ReturnType* ( PL::ConcreteAssetFactory::*)(Args...) const;
    template <typename ReturnType, typename... Args>
    using sptrCAFfn = shared_ptr<ReturnType>( PL::AssetFactoryStore::*)( Args... ) const;
    template <typename ReturnType, typename... Args>
    using vAFSfn = void ( PL::AssetFactoryStore::*)( Args... , shared_ptr<ReturnType> ) const;

    D'où:
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    template< class ReturnType, typename... Args >
    shared_ptr< ReturnType > Get(ptrCAFfn<ReturnType, Args...>,  sptrCAFfn<ReturnType, Args...>, vAFSfbFfn<ReturnType, Args...>,  Args...) const;

    J'ai testé la partie directive using qui est acceptée par le compilateur. Après je ne sais pas ce que donnerait la déduction de type pour get.

  6. #6
    Membre Expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2013
    Messages
    610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Avril 2013
    Messages : 610
    Billets dans le blog
    21
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    PL::ConcreteAssetFactory::*createFunction)(ArgumentsStoreValues... ,ArgumentsCreateFunctionComplementary...)
    Ok mets-toi un instant à la place du compilateur: comment peut-il savoir quels arguments il va nommer ArgumentsStoreValues et quels arguments il va nommer ArgumentsCreateFunctionComplementary? Il ne peut pas: par définition, le nombre d'arguments qu'un template variadique recouvre est indéterminé!
    Donc que faire?
    Il faut donner une façon au compilateur de départager. Tu peux suivre la voie de joe_link_noir, celle des using, ou encore d'autres, par exemple en utilisant des tuples qui regrouperont le type des arguments.

Discussions similaires

  1. Utilisation des templates
    Par vanitom dans le forum MFC
    Réponses: 21
    Dernier message: 01/08/2007, 11h07
  2. Réponses: 1
    Dernier message: 18/04/2006, 12h24
  3. [XSL]portée des templates??
    Par luta dans le forum XSL/XSLT/XPATH
    Réponses: 5
    Dernier message: 23/02/2006, 10h53
  4. [XSL] utilisation des templates
    Par KibitO dans le forum XSL/XSLT/XPATH
    Réponses: 4
    Dernier message: 16/12/2005, 15h54
  5. Utilisation des templates
    Par mikky dans le forum C++
    Réponses: 1
    Dernier message: 14/09/2005, 12h59

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