2 votes

Résultat incorrect pour std::is_trivially_constructible<T, T&>::value quand T a déclaré T::T(T&)

C'est un petit problème qui me perturbe. Je ne sais pas comment le décrire, alors voyez les codes ci-dessous :

struct B {
  B() {}
  B(B&) {
    std::cout << "not trivial\n";
  }
};

int main() {
  B b1;
  B b2(b1);
  std::cout << std::is_trivially_constructible<B,  B&>::value << '\n';
  return 0;
}

Le résultat est le suivant :

not trivial
1

J'utilise VS11.

EDITAR:

Je viens de tester l'exemple dans http://en.cppreference.com/w/cpp/types/is_constructible . Certains résultats sont incorrects.

#include <iostream>
#include <type_traits>

class Foo {
    int v1;
    double v2;
 public:
    Foo(int n) : v1(n), v2() {}
    Foo(int n, double f) : v1(n), v2(f) {}
};
int main() {
    std::cout << "Foo is ...\n" << std::boolalpha
              << "\tTrivially-constructible from const Foo&? "
              << std::is_trivially_constructible<Foo, const Foo&>::value << '\n'
              << "\tTrivially-constructible from int? "
              << std::is_trivially_constructible<Foo, int>::value << '\n'
              << "\tConstructible from int? "
              << std::is_constructible<Foo, int>::value << '\n'
}

Le résultat est le suivant :

Foo is ...
        Trivially-constructible from const Foo&? true
        Trivially-constructible from int? true//Trivially-constructible from int? false
        Constructible from int? true

4voto

Agentlien Points 3163

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;

}

1voto

arne Points 2300

En http://en.cppreference.com/w/cpp/types/is_constructible :

L'"expression du constructeur n'appelle aucune opération qui ne soit pas triviale". et c'est le cas lorsque vous écrivez

B(B&);

Il n'y a rien d'extraordinaire, il suffit de passer une référence.

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