J'aimerais pouvoir me faire un 'factory generique' grace au templates et variadic arguments.
mon probleme viens au moment d'apeller le constructeur .. comment puis-je 'décompresser' la liste d'arguments afin de la transmettre au constructeur. Sinon , comment pourrais-je arriver a mon but ?
Voici ce que je souhaiterais faire ..
class Base{
public:
enum btype{X,Y};
Base(btype t):type_{t}{};
public: btype type_;
};
class A : public Base{
public:std::string value_;int other_;
public:A(std::string c, int o):Base{Base::btype::X},value_{c},other_{o}{}
};
class B : public Base{
public:std::string value_;char other_;
public:B(std::string c, char o):Base{Base::btype::Y},value_{c},other_{o}{}
};
class foo{
public:
template <class T,typename... Args>
static T make(Args... args){
return T(/* args .. */); /** ICI **/
}
};
int main()
{
A a = foo:make<A>("class A",0);
B b = foo::make<B>("class B",'B');
}
Comment pourrais-je arriver a un comportement semblable a ce que je tente de faire dans mon main ?
Merci d'avance pour vos réponses.
EDIT :: Mais quelle question ridicule ... il fallais simplement enlever le commentaire ( je ne croyais pas en fait que args... serais déployé en liste d'argument pour le constructeur ...
- Edité par CrevetteMagique 20 septembre 2017 à 16:33:37
Et pourquoi faire appel au constructeur de ta class via les parenthèses plutôt que les accolades ?
Pour le constructeur j'ai ecris ce code sur coliru tres vite afin de demontrer mn besoin , j'utilise toujours la liste D'initialisation en fait Merci de ta reponse je vais voir pour forward.
edit :: est-ce bien la bonne syntaxe pour le forward ?
return T{std::forward<Args>(args)...};
- Edité par CrevetteMagique 20 septembre 2017 à 17:11:22
Les trucs importants: - Base doit avoir un destructeur virtuel - Base contient, dans le cas pratique, d'autres fonctions virtuelles, parce que sinon, ta factory sers a rien, parce que les types construits sont hétérogènes. - ta factory renvoie probablement un pointeur (ou mieux, un std::unique_ptr) vers ta classe de base. Si ce n'est pas le cas, t'as pas besoin d'une factorty et y'a un truc fumeux dans ta conception. - pour passer les arguments, c'est std::forward<Args>(a)...
- Edité par ledemonboiteux 26 septembre 2017 à 17:29:40
Les trucs importants: - Base doit avoir un destructeur virtuel - Base contient, dans le cas pratique, d'autres fonctions virtuelles, parce que sinon, ta factory sers a rien, parce que les types construits sont hétérogènes. - ta factory renvoie probablement un pointeur (ou mieux, un std::unique_ptr) vers ta classe de base. Si ce n'est pas le cas, t'as pas besoin d'une factorty et y'a un truc fumeux dans ta conception. - pour passer les arguments, c'est std::forward<Args>(a)...
- Edité par ledemonboiteux 25 minutes ago
Pouruqoi avoir mis un string 'what' dans ton factory ? Aussi bien utiliser le template , et si c'est pour 'verifier le type' il ya toujours un static_assert( std::is_base_of<> ... ).
class foo{
public:
template <class T,typename... Args>
static T make(Args... args){
static_assert(std::is_base_of<Base,T>::value, "Invalid Type");
return T(std::forward<Args>(args)...);
}
};
C'est bien un std::unique_ptr renvoyé par ma factory.
Bah tout le but de la factory c'est de découpler pour que le code appelant n'a pas à connaitre les sous types de Base.
Avec des templates comme ça, la factory n'apporte pas grand chose...
Alors je ne vois tout simplement pas la difference entre connaitre le type de base et connaitre sa représentation en string ? Que ca soit le string ou le type , il faut connaitre 'le type' que nous voulons non ?
Non, typiquement la string elle peut venir directement d'un fichier sans qu'on ait à connaitre sa valeur précise.
Et il y a une autre grosse différence, pour pouvoir instancier un type, il faut connaitre sa définition via un include, et ça, c'est lourd.
Mais c'est aussi pour ça que généralement les factory utilisent pour tous les types les même arguments (après, ça reste vague, ça peut être un flux, un dictionnaire, un fichier xml ou json, ...), sans ça il faut de toute façon changer le code appelant selon le type, et encore une fois, la factory ne sert plus à rien.
L'idée typique d'une factory est juste permettre d'avoir un bout de code qui peut charger une collection d'objets héritant tous de la même classe mère, par exemple à partir d'un fichier ou d'un flux utilisateur ou réseau, et ce sans avoir à modifier ce code à chaque fois que tu rajoute une nouvelle classe (violation de l'OCP).
Non, typiquement la string elle peut venir directement d'un fichier sans qu'on ait à connaitre sa valeur précise.
Et il y a une autre grosse différence, pour pouvoir instancier un type, il faut connaitre sa définition via un include, et ça, c'est lourd.
Mais c'est aussi pour ça que généralement les factory utilisent pour tous les types les même arguments (après, ça reste vague, ça peut être un flux, un dictionnaire, un fichier xml ou json, ...), sans ça il faut de toute façon changer le code appelant selon le type, et encore une fois, la factory ne sert plus à rien.
L'idée typique d'une factory est juste permettre d'avoir un bout de code qui peut charger une collection d'objets héritant tous de la même classe mère, par exemple à partir d'un fichier ou d'un flux utilisateur ou réseau, et ce sans avoir à modifier ce code à chaque fois que tu rajoute une nouvelle classe (violation de l'OCP).
Je vois mieu maintenant l'utilisation du string , merci a toi.
Si tu passes le code de l'objet a construire sous la forme d'un paramètre template, c'est que tu le connais a la compilation. Dans ce cas, autant ne pas passer par une factory et construire l'objet directement avec son constructuer ou std::make_unique si on veut un pointeur.
Si tu as besoin d'une factorty, c'est que le type de l'objet à construire n'est pas connu a l'exécution. Il dépend d'un if, est lu dans un fichier, ou que sais-je. Dans ce cas, tudois pouvoir appeler ta factory et décider dynamiquement dedans du type a construire (c.f. cpost de Zérotisme au dessus)
@Zérotisme : sans rapport, mais j'aime bien ce psedo
Si tu passes le code de l'objet a construire sous la forme d'un paramètre template, c'est que tu le connais a la compilation. Dans ce cas, autant ne pas passer par une factory et construire l'objet directement avec son constructuer ou std::make_unique si on veut un pointeur.
Si tu as besoin d'une factorty, c'est que le type de l'objet à construire n'est pas connu a l'exécution. Il dépend d'un if, est lu dans un fichier, ou que sais-je. Dans ce cas, tudois pouvoir appeler ta factory et décider dynamiquement dedans du type a construire (c.f. cpost de Zérotisme au dessus)
@Zérotisme : sans rapport, mais j'aime bien ce psedo
Merci , totalement inspiré de l'anciens nom de ce site
factory generique ?
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
* Un wrapper C++ pour sqlite * Une alternative a boost units
* Un wrapper C++ pour sqlite * Une alternative a boost units