Potrebbe valere la pena che mostra perché è una violazione della const correttezza per eseguire la conversione che si desidera:
#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.
}
Il problema è che vector<int*>.push_back
prende un pointer-to-non-const (che chiamerò un "puntatore non-const" da ora in poi). Ciò significa che potrebbe modificare il punto morto del suo parametro. Specificamente nel caso del vettore, potrebbe restituire il puntatore a qualcun altro che lo modifica. Quindi non è possibile passare un puntatore const alla funzione push_back di w e la conversione desiderata non è sicura anche se il sistema template lo supporta (cosa che non lo è). Lo scopo di const-safety è quello di interrompere il passaggio di un puntatore const a una funzione che accetta un puntatore non-const e in questo modo fa il suo lavoro. C++ richiede di dire in modo specifico se si vuole fare qualcosa di non sicuro, quindi la conversione certamente non può essere implicita. Infatti, a causa del modo in cui i template funzionano, non è possibile affatto (vedi più avanti).
ritengo C++ potrebbe, in linea di principio preservare const-sicurezza consentendo una conversione da vector<T*>&
a const vector<const T*>&
, come int **
per const int *const *
è sicuro. Ma questo è dovuto al modo in cui viene definito il vettore: non sarebbe necessariamente cost-safe per altri template.
Allo stesso modo, in teoria potrebbe consentire una conversione esplicita.E infatti, se non è permessa una conversione esplicita, ma solo per gli oggetti, non i riferimenti ;-)
std::vector<const int*> x(w.begin(), w.end()); // conversion
Il motivo per cui non può farlo per i riferimenti è perché il sistema di modello non può sostenerlo. Un altro esempio che potrebbe essere rotto se la conversione è stato permesso:
template<typename T>
struct Foo {
void Bar(T &);
};
template<>
struct Foo<const int *> {
void Baz(int *);
};
Ora, Foo<int*>
non ha una funzione di Baz. In che modo un puntatore o un riferimento a Foo<int*>
può essere convertito in un puntatore o riferimento a 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?
great, non ho mai pensato a questo –
se questo fosse il motivo, la conversione in 'const vettore' dovrebbe funzionare –
marcin
@marcin: T Hat è teoricamente sicuro, ma non c'è modo per il compilatore di determinarlo senza una conoscenza dettagliata di 'std :: vector'. Inoltre, per renderlo legale richiederebbe una modifica complessa alle regole della sequenza di conversione. Quali sono i requisiti per 'modello classe Foo' per un' Foo 'da trasmettere a' const Foo '? Ricorda, 'Foo' in questo contesto potrebbe essere un modello di puntatore intelligente o qualsiasi altra cosa, non necessariamente un contenitore. –
MSalters