11
votes

Conflit entre le constructeur de copie et le constructeur de transfert

Ce problème est basé sur le code qui fonctionne pour moi sur GCC-4.6 mais pas pour un autre utilisateur avec Clang-3.0, à la fois en mode C ++ 0x. XXX

Un objet de < Code> MyBase peut prendre toute liste d'arguments du constructeur, tant que t prend en charge cette signature de construction. Le problème concerne les fonctions de membre spécial.

  1. IIUC, le modèle de constructeur annule le constructeur par défaut défini automatiquement. Cependant, étant donné que le modèle peut accepter zéro argument, il agira comme un constructeur par défaut explicitement défini (tant que t est constructible par défaut).
  2. IIUC, la détermination d'une stratégie de la copie-construction d'une classe ignore les modèles de constructeur. Cela signifie dans ce cas que mybase gagnera un constructeur de copie défini automatiquement (tant que t est copié) qui change t copie -Construction.
  3. Appliquez également l'étape précédente pour la construction de déplacement.

    donc si je passe un mybase const & comme argument de constructeur unique, quel constructeur est appelé, le transfert d'un ou de la copie implicite d'un? < Pré> xxx

    Le problème de mon utilisateur utilisait ceci en tant que classe de base. Le compilateur s'est plaint que sa classe ne puisse pas synthétiser un constructeur de copie défini automatiquement, car il ne pouvait pas trouver de correspondance avec le modèle de constructeur de la classe de base. N'a-t-il pas appeler myBase Copy-constructeur automatique pour son propre constructeur de copie automatique? Est enraciné par une erreur pour atteindre un conflit?


5 commentaires

Question interessante. Je recommande de faire un SSCCE (voir sscce.org ) qui fonctionne dans GCC et échoue à Clang pour nous aider à comprendre le problème mieux et le recréer nous-mêmes. De plus, veuillez nous donner le message d'erreur exact de Clang.


En fait, une version de GCC relativement proche de la tête (à partir de 20120202) n'accepte pas également ce code. Il semble que le constructeur de transfert est ramassé même pour la copie. Je ne suis pas tout à fait sûr pourquoi cela. Il n'est pas lié à la "syntaxe d'initialisation uniforme": même lorsque vous utilisez des parenthèses pour la dernière déclaration, il ne compile pas.


Mon code est quelque chose que j'ai écrit une décennie il y a une décennie et mis à jour pour C ++ 11 la semaine dernière. Je ne sais pas comment travailler tout le système TRAC de Boost, mais vous pouvez regarder My changements et le Etat actuel de le fichier (à la révision 77031 à cet écriture).


J'ai trouvé une archive de courrier avec le Description du problème .


Fyi Scott Meyers a discuté de ce problème sur son blog sur Scottmeyers.blogspot. COM / 2012/10 / ...


3 Réponses :


10
votes

Je suis juste dans le bar avec Richard Corden et entre nous, nous avons conclu que le problème n'a rien à voir avec des variadiques ou des avales. La construction de copie générée implicitement dans ce cas prend un myBase const & code> comme argument. Le constructeur modélisé déduit le type d'argument comme myBase & code>. C'est un meilleur match qui s'appelle bien que ce ne soit pas un constructeur de copie.

L'exemple de code que j'ai utilisé pour tester est-ce: p> xxx pré>

I nécessaire pour supprimer le Utilisation des listes d'initialistes car ce n'est pas encore pris en charge par Clang. Cet exemple compile à l'exception de l'initialisation de fv3 code> qui échoue: le constructeur de copie synthétisé pour myBase code> prend un mybase const & code> et Ainsi, passe fv2 code> appelle le constructeur variadidique transférant l'objet à la classe de base. p>

J'ai peut-être mal compris la question mais basée sur d0 code> et et D1 CODE> Il semble que le constructeur par défaut et un constructeur de copie soient synthétisés. Cependant, il s'agit de jolies versions à jour de GCC et de Clang. C'est-à-dire que cela n'explique pas pourquoi aucun constructeur de copie n'est synthétisé car il y a une synthétisée. P>

Pour souligner que ce problème n'a rien à voir avec des listes d'arguments variadiques ou des r devalues: le code suivant montre le problème que Le constructeur modélisé est appelé, bien qu'il semble que un constructeur de copie soit appelé et que les constructeurs de copies ne sont jamais des modèles. C'est en fait un comportement quelque peu surprenant que j'étais certainement ignorant: p> xxx pré>

En conséquence, ajout d'un constructeur variadique comme dans la question à une classe qui n'a pas d'autre Les constructeurs modifient les constructeurs de copie de comportement fonctionnent! Personnellement, je pense que c'est plutôt regrettable. Cela signifie efficacement que la classe mybase code> doit également être augmentée avec copie et déplacer des constructeurs également: p> xxx pré>

Malheureusement, cela ne semble pas fonctionner Avec GCC: il se plaint des constructeurs de copies par défaut (il affirme que le constructeur de copie par défaut prenant une référence non Const ne peut pas être défini dans la définition de la classe). Clang accepte ce code sans plainte. Utilisation d'une définition du constructeur de copie prenant une référence non-Const fonctionne avec GCC et CLANG: P>

template <typename T> MyBase<T>::MyBase(MyBase<T>&) = default;


2 commentaires

@MOOINGDUCK: Je ne pouvais pas reproduire un problème d'utilisation d'une classe de base correspondante (voir ma mise à jour de la réponse).


Oui, j'ai annoncé des noms différents à l'origine et DUD ne mettez pas à jour tous les endroits. J'espère que j'ai réparé tout maintenant.



2
votes

J'ai personnellement eu le problème des instantanés de la GCC depuis un certain temps maintenant. J'ai eu du mal à comprendre ce qui se passait (et si cela était autorisé) mais je suis arrivé à une conclusion similaire que Dietmar Kühl: Les constructeurs de copie / déplacement sont toujours ici, mais ne sont pas toujours préférés à travers la mécanique de la surcharge Résolution.

J'utilise cela pour contourner le problème pendant un certain temps maintenant: p> xxx pré>

en utilisant avec un constructeur comme le vôtre ressemblerait à: P >

template<
    typename... Args
    , typename = typename enable_if_unrelated<MyBase, Args...>::type
>
MyBase(Args&&... args);


0 commentaires

0
votes

J'ai évoqué la réponse de Dietmar parce que je suis totalement d'accord avec lui. Mais je veux partager une "solution" que j'utilisais quelque temps plus tôt pour éviter ces problèmes:

J'ai intentionnellement ajouté un paramètre factice au constructeur variadique: xxx

surtout Étant donné que le constructeur accepterait quelque chose sans ce paramètre factice, il semble approprié de rendre le code d'utilisateur explicitement choisir le bon constructeur par (en quelque sorte) "nommer" it.

Ce n'est peut-être pas possible dans votre cas. Mais parfois, vous pouvez vous en tirer.


0 commentaires