7
votes

Constructeurs et itérateurs Explicites C ++

Considérez le code suivant:

#include <vector>

struct A
{
    explicit A(int i_) : i(i_) {}
    int i;
};

int main()
{
    std::vector<int> ints;
    std::vector<A> As(ints.begin(), ints.end());
}


3 commentaires

Réponse indirectement ici: Stackoverflow.com/Questtions/1943228/...


Je viens d'écrire une réponse ici en fonction de cette question + réponse, mais cela ne s'applique pas vraiment, car std :: vecteur :: itérateur n'est pas un type intégral, et le remplissage constructeur n'est pas appelé. Donc je l'ai supprimé. Je pense que tout ce que je peux dire, c'est que la norme ne interdit Conversion explicite dans tout constructeur de conteneurs.


Vs 2010 Beta se comporte comme Comeau et GCC.


6 Réponses :



0
votes

Ce code ne compile pas à Comeau:

Foo foo = (Foo)5;


0 commentaires

0
votes

Oui, il devrait compiler. Si le constructeur n'est pas utilisé, son explicite n'est pas un problème.


3 commentaires

Si le constructeur n'est pas utilisé, comment autrement conversons-nous d'un INT à un A?


Rien n'est créé et rien n'est converti - les deux vecteurs sont vides


Le comportement est le même si quelque chose est inséré dans le vecteur "INTS" avant la construction de "comme".



1
votes

C'est une question plutôt délicate, et peut-être que VisualStudio ait raison et le comeau faux (cela semble vraiment difficile à croire).

La norme Si Word Lisez par mot, définit ce constructeur de vecteur en termes de Copier constructeur (voir citation), et cela signifie littéralement que l'objet obtenu par la déséroférance doit d'abord être converti en Le type T, puis le constructeur de copie doit être appelé. À ce stade, avec un constructeur explicite, le code ne doit pas compiler.

Il semble raisonnable de s'attendre à une implémentation, d'autre part, d'appeler directement un constructeur prenant comme argument l'itérateur déréférencé, auquel cas la L'appel du constructeur serait explicite et le code devrait donc compiler. Cela irait à l'encontre de la formulation exacte de la citation ci-dessous, car le constructeur copy est défini pour un type donné T comme constructeur qui prenant une seule référence éventuellement constante à un objet de type T.

Je ne peux penser à un argument raisonnable de ne pas utiliser l'approche Comeau, et je pense que c'est juste un avis personnel) est que le libellé de la norme en ce qui concerne la complexité du constructeur de vecteur devrait probablement être retraité comme nécessitant seulement n appels vers le constructeur T approprié , le cas échéant, il faudrait être défini comme le constructeur qui correspond à l'appel t (* premier) (c'est-à-dire une prise de constructeur Un INTTÉTRATEDATORATOR :: VALUE_TYPE (par valeur ou éventuellement une référence constante), ou le constructeur de copie T après une conversion implicite de INTTÉTRATORATOR :: value_type à t. < p> 23.2.4.1 [lib.vector.cons] / 1

Complexité: le vecteur de modèle de constructeur (INTTÉTRAITOR Tout d'abord, l'intrigeur dernier) ne fait que N Appels vers le constructeur de copie de T (où n est la distance entre premier et dernier) et aucune réaffectation Si les itérateurs d'abord et dernier sont de transmettre, bidirectionnel ou aléatoire Catégories d'accès. Ça rend la commande n appelle au constructeur de copie de T et Commandez le journal des réaffectations s'ils sont juste des itérateurs d'entrée.

Je voudrais savoir comment le compilateur VS se comporte lorsque vous indiquez: xxx

avec g ++ Le résultat est que T2 :: opérateur T1 < / code> n'est pas appelé, mais les éléments de v1 sont construits directement à partir des éléments dans v2 . Je suppose que avec vs le compilateur utiliserait t1 :: opérateur t1 pour convertir de chaque élément dans v2 à un élément T1, puis appelez le constructeur de copie. Est-ce vrai?


2 commentaires

En fait, essayant de compiler votre code avec le compilateur VS donne une erreur (C2664): 'std :: allocator <_ty> :: construction': impossible de convertir le paramètre 2 de 'T2' en 'const T1 &' avec [_ty = T1] Raison: impossible de convertir de "T2" en "const t1" Aucun opérateur de conversion défini par l'utilisateur disponible pouvant effectuer cette conversion ou que l'opérateur ne peut pas être appelé.


Je viens de tester avec VS2010 Beta, et cela compile non seulement, mais s'exécute avec le même comportement que g ++: le constructeur t1 (t2 const &) est appelé.



1
votes

Cela revient vraiment à une question de la manière dont la bibliothèque STL est mise en œuvre et non une question de spécification de langue. Il n'y a rien dans la spécification de la langue qui l'interdirait de travailler, pas plus que cela n'exigerait rien que cela fonctionne.

Si le constructeur STL :: vecteur a été écrit pour essayer une conversion implicite à l'aide de l'opérateur d'affectation, alors cela échouerait. Il est plus probable que l'implémentation Microsoft STL utilise l'optimisation de la valeur de retour lors de l'initialisation via un appel de constructeur, auquel cas ce code fonctionnerait bien.

Il est important de noter que la seule raison de ce travail est que le constructeur de vecteur STL :: vecteur est modélisé et la seule exigence est qu'il s'agit d'un altérateur, ou de plus précisément qu'il prend en charge toutes les fonctionnalités requises d'un itérateur d'entrée. .

J'aimerais également souligner que ceci est un excellent exemple de la raison pour laquelle il est souvent difficile d'écrire un code multi-plate-forme. Parfois, vous vous retrouvez avec des problèmes dans lesquels ni le compilateur ne dévient nécessairement de la norme linguistique, mais le code n'est toujours pas portable.


0 commentaires