2010-06-25 7 views
17

Quelle est la bonne façon de transférer tous les constructeurs du parent en C++ 0x?Transférer tous les constructeurs en C++ 0x

Je fais ceci:

class X: public Super { 
    template<typename... Args> 
     X(Args&&... args): Super(args...) {} 
}; 
+0

Existe-t-il une raison pour ne pas taper tous les constructeurs plutôt que d'utiliser un raccourci de modèle? –

+10

Oui, l'heure, et si la Super classe est mise à jour, alors il sera dans un gâchis de maintenance. La solution automatisée est infiniment supérieure. – Puppy

+1

@DeadMG - Pas vraiment. Alors que faire si la base obtient un nouveau constructeur? Le dérivé n'a pas besoin de l'utiliser sauf si les nouvelles informations sont requises. A partir de là, cette "solution" automatisée pousse simplement le traitement de cette question à tous les clients de dérivés. Plus souvent qu'autrement, c'est complètement la mauvaise chose à faire. Dérivé ne devrait pas être mis à jour à moins qu'il y ait un objet qui en a besoin et il devrait être fait explicitement pour qu'il soit évident de construire l'objet en regardant son constructeur. Réserver des modèles variés pour les conditions variadiques. –

Répondre

39

Il y a une meilleure façon en C++ 0x pour cette

class X: public Super { 
    using Super::Super; 
}; 

Si vous déclarez un modèle parfait-transfert, votre type se comporte mal dans la résolution de surcharge. Imaginez votre classe de base est convertible de int et il existe deux fonctions pour imprimer les classes

class Base { 
public: 
    Base(int n); 
}; 

class Specific: public Base { 
public: 
    template<typename... Args> 
    Specific(Args&&... args); 
}; 

void printOut(Specific const& b); 
void printOut(std::string const& s); 

Vous appelez avec

printOut("hello"); 

ce qu'on appellera? C'est ambigu, car Specific peut convertir n'importe quel argument, y compris les tableaux de caractères. Il le fait sans tenir compte des constructeurs de classe de base existants. Hériter des constructeurs à l'aide de déclarations déclare uniquement les constructeurs nécessaires pour que cela fonctionne.

+0

IMHO - c'est la réponse qui aurait dû être acceptée même si l'autre répond directement à la question posée. –

+0

Merci Johannes. @Noah Roberts: Oui. –

+1

Je me demande simplement si le mot-clé 'explicit' ne rendrait pas l'appel sans ambiguïté tout en permettant au modèle de transfert parfait de fonctionner. Je ne recommanderais pas de générer automagiquement des constructeurs dérivés ... –

5

Je pense que vous devez faire Super(std::forward<Args>(args)...) si vous voulez que les choses transmises correctement. args a un nom, donc je crois qu'il se liera aux références régulières avant les références rvalue. Cependant, plus important encore, vous ne transférerez pas les constructeurs de copie de cette façon. Le compilateur en générera toujours un pour vous, car il ne considère pas les constructeurs de templates. Dans l'exemple fourni, tout va bien, parce que le compilateur que l'on a créé appellera simplement le constructeur de copie parent de toute façon, ce qui est exactement ce que vous voulez. Si ce n'est pas approprié dans un cas plus compliqué, alors vous devrez l'écrire vous-même.

+1

'Super (std :: forward (args) ...)' est correct, donc vous étiez assez proche. Rappelez-vous, forward nécessite un argument de modèle explicite. – Puppy

+0

Je l'avais à l'origine, puis je me suis deviné.Merci pour la correction. –

+0

C'est génial. Avez-vous une intuition sur ce que std :: forward fait? (Est-ce le premier ordre?) Pourquoi ne pouvons-nous pas écrire "args ..."? Cela entraînerait-il l'appel de constructeurs de copie? –

Questions connexes