8

vector<T> a un constructeur qui prend la taille du vecteur, et pour autant que je sais qu'il est explicite, qui peut être prouvé par le fait que le code suivant ne peut pas compilerConversion implicite de int en vecteur?

void f(std::vector<int> v); 
int main() 
{ 
    f(5); 
} 

Qu'est-ce que je ne peux pas comprendre et je vous demande d'expliquer est pourquoi le code suivant compile

std::vector<std::vector<int>> graph(5, 5); 

Non seulement il compile, il redimensionne réellement graphique à 5 et définit chaque élément à un vecteur de cinq zéros, soit le même effet que serait le code j'écrirais normalement:

std::vector<std::vector<int>> graph(5, std::vector<int>(5)); 

Comment? Pourquoi?

compilateur: MSVC10.0


OK, semble que c'est un bug MSVC (encore un autre). Si quelqu'un peut élaborer sur le bogue dans une réponse (à savoir résumer les cas où il est reproduit) Je serais heureux de l'accepter

+4

Ceci (à juste titre) ne compile pas sur GCC 4.7. Encore un autre bizutage non-standard de MSVC++. Ils ont probablement juste oublié de marquer le constructeur 'explicite', vous pouvez creuser' 'pour vérifier cela. – syam

+0

@syam: Je suis heureux de le chauffer, il ne compile pas sur GCC, mais ce qui est vraiment bizarre, c'est que le premier exemple compile sur MSCV, tandis que l'autre ne le fait pas. C'est vraiment étrange –

+0

@ArmenTsirunyan Ni compile sur VS2012; le message d'erreur indique que le constructeur est 'explicite' – Praetorian

Répondre

7

Ce n'est pas vraiment un bug. La question est de savoir ce qui pourrait mal se passer pour permettre le deuxième morceau de code alors que le premier ne compile pas?

La question est que bien qu'il semble évident pour vous ce constructeur que vous voulez appeler quand vous faites:

std::vector<std::vector<int>> graph(5, 5); 

il est pas clair pour le compilateur. En particulier, il y a deux surcharges de constructeur qui peuvent potentiellement accepter les arguments:

vector(size_type,const T& value = T()); 

template <typename InputIterator> 
vector(InputIterator first, InputIterator last); 

La première exige la conversion de 5-size_type (qui est non signé), tandis que le second est un match parfait, donc ce sera la un ramassé par le compilateur ...

...mais le compilateur exige que la deuxième surcharge, si le type est InputIterator déduite intégrale se comporte comme si elle était un appel à:

vector(static_cast<size_type>(first),static_cast<T>(last)) 

Qu'est-ce que la norme C++ 03 exige effectivement que le second argument est explicitement converti à partir du type d'origine int vers le type de destination std::vector<int>. Parce que la conversion est explicite, vous obtenez l'erreur. Le standard C++ 11 modifie le libellé pour utiliser SFINAE pour désactiver le constructeur d'itérateur si l'argument n'est pas vraiment un itérateur d'entrée, donc dans un compilateur C++ 11, le code doit être rejeté (ce qui est probablement la raison certains ont prétendu que c'était un bug).

-4

std :: vector < int> a constructeur qui accepte size_type et const int &. C'est le constructeur que je m'attendrais à appeler dans ce cas, en initialisant le vecteur pour avoir 5 ints, chacun avec la valeur 5.

+3

Comme vous pouvez le lire clairement dans ma question, cela ne * * –

+0

@ArmenTsirunyan Bogue du compilateur. – selalerer

+0

Dans quel cas votre réponse n'a aucun sens –

1

Ceci est en fait une extension, pas un bug.

Le constructeur appelé est celui qui prend deux itérateurs (mais en réalité, la signature correspond à deux paramètres du même type); il appelle ensuite une spécialisation pour quand les deux itérateurs sont réellement int, qui construit explicitement un value_type en utilisant la valeur de end et remplit le vecteur avec begin copies de celui-ci.

+0

Je ne pense pas que je comprenne ... Qu'est-ce que int signifie comme un itérateur? –

+0

@ArmenTsirunyan: 'std :: vector' a un constructeur qui prend un itérateur de début et de fin. Il est défini comme quelque chose comme 'template vector (_It first, _It last)', qui correspond à votre invocation.Il appelle ensuite une fonction avec diverses surcharges basées sur le type de '_It', l'une des surcharges gérant le cas où' _It' est un 'int'. –

+0

Pour répondre à votre question, c'est __not__ un itérateur, mais le code gère le cas où vous lui donnez un int. –

2

Pour moi, ça ressemble qu'il appelle ce constructeur:

template <class InputIterator> 
vector (InputIterator first, InputIterator last, 
    const allocator_type& alloc = allocator_type()); 

Je ne sais pas où explicit vient en elle, parce que le constructeur prend plusieurs paramètres. Ce n'est pas la conversion automatique d'un int en un vecteur.

+0

La norme interdit explicitement l'utilisation du constructeur à deux itérateurs lorsque l'autre constructeur serait également une correspondance possible. –

+0

Je ne pense pas que je comprends ... Comment est int un itérateur d'entrée? –

+0

'InputIterator' est juste le paramètre du template - il peut être n'importe quel type. –