MISE À JOUR FINALE
Après un commentaire très perspicace de @SebastianRedl, j'ai réalisé que l'intention de la norme est de se référer à l'ensemble de la construction de l'objet, et pas seulement aux opérations à l'intérieur du constructeur. Cela signifierait qu'il y a effectivement un bogue dans Visual C++. Cependant, je reste d'avis que la formulation de la norme n'est pas suffisamment claire, et je laisserai donc le reste de ma réponse inchangée pour la postérité.
Pour clarifier : le comportement mentionné par l'OP est en fait un bug, et à la lumière de cela, la plupart de ce que je dis en dessous de cette mise à jour est erroné.
Fin de la mise à jour
En fait, il ne s'agit pas d'un bogue du compilateur, mais plutôt d'une bizarrerie de la norme, et votre confusion est donc compréhensible.
Selon la norme C++11, les conditions suivantes s'appliquent is_trivially_constructible::value
être true
.
§20.9
is_constructible<T,Args...>::value
est vrai et la définition de la variable is_constructible
, tel que défini ci-dessous, n'appelle aucune opération qui ne soit pas triviale
Ainsi, is_trivially_constructible
est vrai tant que le type donné est constructible avec les arguments donnés et qu'il n'appelle pas d'opérations non triviales. Votre exemple n'inclut qu'un seul constructeur de ce type, un constructeur de copie. En fait, d'après la définition d'une "opération non triviale" (essentiellement un opérateur ou un constructeur non trivial), cela s'applique à votre type. Ainsi, en retournant true
est correcte.
Cependant, il y a un point très étrange ! La norme C+11 dit ce qui suit à propos des constructeurs de copies :
§12.8.12 (souligné par moi)
A Constructeur de copie/déplacement pour la classe X est triviale si elle est non fourni par l'utilisateur et si
- la classe X n'a pas de fonctions virtuelles (10.3) ni de classes de base virtuelles (10.1), et
- le constructeur choisi pour copier/déplacer chaque sous-objet direct de la classe de base est trivial, et
-
pour chaque membre de données non statique de X qui est de type classe (ou tableau), le constructeur choisi pour copier/déplacer ce membre est trivial ;
sinon le constructeur de copie/déplacement n'est pas trivial.
Puisque vous fournissez un constructeur de copie défini par l'utilisateur, votre classe n'est pas trivialement constructible par copie. Le constructeur de copie que vous avez fourni n'est pas trivial. Néanmoins, le constructeur de copie non trivial hace remplissent les critères nécessaires pour is_trivially_constructible
pour revenir true
avec un argument qui correspond à votre constructeur de copies.
À mon avis, il s'agit plutôt d'un "bogue" dans la norme. is_trivially_constructible
renvoie si le type est trivialement constructible compte tenu de certains arguments. Cela ne semble pas garantir que le constructeur lui-même soit considéré comme trivial !
Mise à jour :
Après avoir essayé de concevoir un test pour montrer le cas suivant, j'ai trouvé un bug dans VC11. La logique décrite par la norme signifie que, si B
est utilisé comme sous-objet (membre ou base) d'un autre type, tout constructeur de ce type qui invoque le constructeur de copie de B
doit être considérée comme non trivial par std::is_trivially_constructible
. Ce n'est pas le cas dans la VC11.
Exemple de code
#include <iostream>
#include <type_traits>
struct B
{
B() {}
B(B&) {
std::cout << "not trivial\n";
}
};
struct A : B
{
A(B& B) : b(B){}
B b;
};
int main()
{
std::cout << std::is_trivially_constructible<B, B&>::value << '\n'; // Should print 1
std::cout << std::is_trivially_constructible<A, B&>::value << '\n'; // Should print 0
getchar();
return 0;
}