57 votes

Pourquoi le déplacement de classe dérivée est-il constructible quand la classe de base ne l'est pas?

Prenons l'exemple suivant:

 #include <iostream>
#include <string>
#include <utility>

template <typename Base> struct Foo : public Base {
    using Base::Base;
};

struct Bar {
    Bar(const Bar&) { }
    Bar(Bar&&) = delete;
};

int main() {
    std::cout << std::is_move_constructible<Bar>::value << std::endl; // NO
    std::cout << std::is_move_constructible<Foo<Bar>>::value << std::endl; // YES. Why?!
}
 

Pourquoi le compilateur génère-t-il un constructeur de déplacements alors que la classe de base est non constructible à la construction?

Est-ce dans la norme ou s'agit-il d'un bogue du compilateur? Est-il possible de "propager parfaitement" la construction de déplacement de la classe de base à la classe dérivée?

30voto

Brian Points 15388

Parce que:

Un défaut constructeur de déplacement qui est défini comme étant supprimés est ignoré par la résolution de surcharge.

([classe.copie]/11)

Bars'constructeur de déplacement est explicitement supprimées, alors Bar ne peut pas être déplacé. Mais Foo<Bar>s'constructeur de déplacement est implicitement supprimé après avoir été déclarée implicitement en tant que par défaut, en raison du fait que l' Bar membre ne peut pas être déplacé. Par conséquent, Foo<Bar> peut être déplacé à l'aide de son constructeur de copie.

Edit: j'ai aussi oublié de mentionner le fait important qu'un hériter du constructeur déclaration comme using Base::Base n'hérite pas de défaut, de copier ou de déplacer des constructeurs, et c'est pourquoi, Foo<Bar> n'ont pas explicitement supprimé déplacer constructeur hérité de l' Bar.

24voto

songyuanyao Points 2265

1. Le comportement de l' std::is_move_constructible

Ce comportement est attendu de std::is_move_constructible:

Sans un constructeur de déplacement, mais avec un constructeur de copie qui accepte const T& arguments, satisfaire std::is_move_constructible.

Ce qui signifie avec un constructeur de copie, il est toujours possible de construire T de référence rvalue T&&. Et Foo<Bar> a Implicitement déclaré constructeur de copie.

2. La implicitement déclarées constructeur de déplacement de l' Foo<Bar>

Pourquoi ne compilateur génère constructeur de déplacement en dépit de la classe de base non-déplacer constructible?

En fait, le constructeur de déplacement de l' Foo<Bar> est défini comme étant supprimés, mais notez que l'supprimé implicitement déclarées constructeur de déplacement est ignoré par la résolution de surcharge.

La implicitement déclarées ou défaut constructeur de déplacement pour la classe Test définie comme supprimé dans une des conditions suivantes est remplie:

...
T has direct or virtual base class that cannot be moved (has deleted, inaccessible, or ambiguous move constructors); 
...

L'supprimé implicitement déclarées constructeur de déplacement est ignoré par la résolution de surcharge (sinon il serait d'empêcher la copie de l'initialisation de rvalue).

3. La différence de comportement entre Bar et Foo<Bar>

Notez que le constructeur de déplacement de l' Bar est déclaré en tant que deleted explicitement, et le constructeur de déplacement de l' Foo<Bar> est implicitement déclarée et définie en tant que deleted. Le point est que l'supprimé implicitement déclarées constructeur de déplacement est ignoré par la résolution de surcharge, ce qui permet de se déplacer en construire Foo<Bar> avec son constructeur de copie. Mais la suppression explicite déplacer constructeur de participer à la résolution de surcharge, signifie que lorsque vous essayez de déplacer constructeur Bar supprimés constructeur de déplacement sera sélectionné, alors le programme est mal formé.

C'est pourquoi, Foo<Bar> est constructible mais Bar ne l'est pas.

Le standard a une déclaration explicite à ce sujet. $12.8/11 la Copie et le déplacement des objets de la classe [classe.copier]

Un défaut constructeur de déplacement qui est défini comme étant supprimés est ignoré par la résolution de surcharge ([- dessus.match], [- dessus.plus]). [ Remarque: la suppression du constructeur de déplacement serait interférer avec initialisation à partir d'une rvalue qui peut utiliser le constructeur de copie à la place. - la note de fin ]

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X