2015-04-16 7 views
2

Tenir compte de cette classe:Quelle est la spécification d'exception pour une opération de déplacement par défaut définie en dehors de la classe?

class C1 { 
    C1(C1&&) = default;  // declare and define move ctor 
}; 

Parce que cteur de déplacement de C1 est explicitement défaut sur sa première déclaration, 8.4.2 de la norme nous dit qu'il a la même spécification d'exception (ES) comme si la fonction avait été implicitement déclaré . On peut alors utiliser 15.4/14 et 12.8/15 pour conclure que son ES est noexcept(true).

Considérons maintenant une classe C2 qui est le même, à l'exception de son déplacement cteur est réglé par défaut en dehors de la définition de la classe:

class C2 { 
    C2(C2&&);     // declare move ctor 
}; 

C2::C2(C2&&) = default;  // define move ctor 

Quel est l'ES pour le cteur de déplacement de C2? Parce que ce n'est pas par défaut sur sa première déclaration, 8.4.2/2 ne s'applique pas. Parce qu'il n'a pas d'ES explicite, 8.4.2/3 ne s'applique pas. Parce que ce n'est pas implicitement déclaré, 15.4/14 ne s'applique pas. De ce que je peux dire, cela signifie que 15.4/12 s'applique, et il dit que la fonction par défaut ES est noexcept(false). Si j'ai raison, cela signifie que le mouvement ctor dans C1 est noexcept(true), mais le mouvement conceptuellement identique ctor dans C2 est noexcept(false).

Mon raisonnement sur C2 est-il correct?

+0

en regardant le [projet] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3376.pdf), je ne vois pas où il spécifie qu'il a besoin être par défaut sur la ** première déclaration **. L'esprit élaborant cela? –

+0

Vérifiez 8.4.2/2 et 8.4.2/3 de la spécification C++ 14. – KnowItAllWannabe

+1

La différence entre les deux est que 'C2 :: C2 (C2 &&) = default;' pourrait être dans une unité de traduction différente (et en fait, doit être dans exactement une unité de traduction). Le code qui ne voit que la déclaration C2 (C2 &&); 'n'a d'autre choix que de supposer le pire.) D'autre part, la définition de 'C1' doit être répétée dans toutes les unités de traduction (sous ODR). conclure indépendamment que le constructeur ne jette pas –

Répondre

6

Oui, votre interprétation est correcte, et si vous faites vos déclarations publiques, il est facile de montrer que les deux clang et gcc sont d'accord avec votre raisonnement:

#include <type_traits> 

class C1 
{ 
public: 
    C1(C1&&) = default;  // declare and define move ctor 
}; 

class C2 { 
public: 
    C2(C2&&);     // declare move ctor 
}; 

C2::C2(C2&&) = default;  // define move ctor 

int 
main() 
{ 
    static_assert(std::is_nothrow_move_constructible<C1>{}, ""); 
    static_assert(!std::is_nothrow_move_constructible<C2>{}, ""); 
} 
1

L'interprétation est correcte, oui. La mise en défaut après la première déclaration signifie générer le corps de la fonction sans effectuer de magie sur la déclaration. Si la définition est dans une unité de traduction différente, vous pouvez librement basculer entre

C2::C2(C2&& rhs) {/* hand-written implementation here */} 

et

C2::C2(C2&& rhs) = default; 

et ce n'est pas visible pour les utilisateurs de la classe. Puisque vous n'avez pas par défaut sur la première déclaration, la déclaration est effectivement noexcept (faux) et (pour le meilleur ou pour le pire) reste ainsi indépendamment des sous-objets de votre classe. En cas de défaut lors de la première déclaration, la "magie" est de nouveau activée. En effet, la spécification noexcept de votre déclaration peut également être générée.

+0

ah, sauf que même une fonction membre spéciale par défaut après sa première déclaration (aka en dehors de la définition de classe) doit correspondre à la définition implicite en ce qui concerne la spécification noexcept. –