Il peut être utile de montrer pourquoi il est une violation de const-correct pour effectuer la conversion que vous voulez:
#include <vector>
const int a = 1;
void addConst(std::vector<const int *> &v) {
v.push_back(&a); // this is OK, adding a const int* to a vector of same
}
int main() {
std::vector<int *> w;
int b = 2;
w.push_back(&b); // this is OK, adding an int* to a vector of same
*(w.back()) = 3; // this is OK, assigning through an int*
addConst(w); // you want this to be OK, but it isn't...
*(w.back()) = 3; // ...because it would make this const-unsafe.
}
Le problème est que vector<int*>.push_back
prend un pointeur vers non-const (que j'appellerai désormais un "pointeur non-const"). Cela signifie qu'il pourrait modifier la pointe de son paramètre. Spécifiquement dans le cas du vecteur, il peut renvoyer le pointeur à quelqu'un d'autre qui le modifie. Vous ne pouvez donc pas passer un pointeur const à la fonction push_back de w, et la conversion que vous voulez n'est pas sûre même si le système de template la supporte (ce qui n'est pas le cas). Le but de const-safety est de vous empêcher de passer un pointeur de const à une fonction qui prend un pointeur non-const, et c'est comme ça qu'elle fait son travail. C++ vous oblige à dire spécifiquement si vous voulez faire quelque chose de dangereux, donc la conversion ne peut certainement pas être implicite. En fait, à cause du fonctionnement des templates, ce n'est pas possible du tout (voir plus loin).
Je pense que C++ pourrait, en principe, conserver en permettant une conversion vector<T*>&
-const vector<const T*>&
const-sécurité, tout comme int **
à const int *const *
est sûr. Mais c'est à cause de la façon dont le vecteur est défini: il ne serait pas nécessairement sécurisé pour les autres modèles. De même, il pourrait en théorie permettre une conversion explicite.En fait, elle permet une conversion explicite, mais seulement pour les objets, pas de références ;-)
std::vector<const int*> x(w.begin(), w.end()); // conversion
La raison pour laquelle il ne peut pas le faire pour des références est parce que le système de modèle ne peut pas supporter. Un autre exemple qui serait rompu si la conversion a permis:
template<typename T>
struct Foo {
void Bar(T &);
};
template<>
struct Foo<const int *> {
void Baz(int *);
};
Maintenant, Foo<int*>
ne possède pas de fonction Baz. Comment diable un pointeur ou une référence à Foo<int*>
peut-il être converti en un pointeur ou une référence à Foo<const int*>
?
Foo<int *> f;
Foo<const int *> &g = f; // Not allowed, but suppose it was
int a;
g.Baz(&a); // Um. What happens? Calls Baz on the object f?
super, je n'ai jamais pensé à cela –
si c'était la raison, la conversion en 'const vecteur' devrait fonctionner –
marcin
@marcin: T C'est théoriquement sûr, mais il n'y a aucun moyen pour le compilateur de le déterminer sans une connaissance détaillée de 'std :: vector'. De plus, pour le rendre légal, il faudrait modifier de façon complexe les règles de la séquence de conversion. Quelles sont les exigences sur le 'modèle classe Foo' pour un' Foo 'à être casté à un' Foo Foo '? Rappelez-vous, 'Foo' dans ce contexte pourrait être un modèle de pointeur intelligent ou autre chose, pas nécessairement un conteneur. –
MSalters