2011-05-12 8 views
288
#include <iostream> 
#include <set> 

using namespace std; 

class StudentT { 

public: 
    int id; 
    string name; 
public: 
    StudentT(int _id, string _name) : id(_id), name(_name) { 
    } 
    int getId() { 
     return id; 
    } 
    string getName() { 
     return name; 
    } 
}; 

inline bool operator< (StudentT s1, StudentT s2) { 
    return s1.getId() < s2.getId(); 
} 

int main() { 

    set<StudentT> st; 
    StudentT s1(0, "Tom"); 
    StudentT s2(1, "Tim"); 
    st.insert(s1); 
    st.insert(s2); 
    set<StudentT> :: iterator itr; 
    for (itr = st.begin(); itr != st.end(); itr++) { 
     cout << itr->getId() << " " << itr->getName() << endl; 
    } 
    return 0; 
} 

En línea:error: xxx pasar como 'este' argumento de los descartes calificadores xxx

cout << itr->getId() << " " << itr->getName() << endl; 

Se da un error que:

../main.cpp:35: error: passing 'const StudentT' as 'this' argument of 'int StudentT::getId()' discards qualifiers

../main.cpp:35: error: passing 'const StudentT' as 'this' argument of 'std::string StudentT::getName()' discards qualifiers

Qué le pasa a este código? ¡Gracias!

+11

¿Dónde está la línea 35 en el fragmento de código? –

+56

Deseo que GCC mejore este mensaje de error, p. "descarta los calificadores" -> "rompe const correctness" – jfritz42

+12

@ jfritz42: Sería confuso para el caso en que descarte 'volátil' – PlasmaHH

Respuesta

338

Los objetos en el std::set se almacenan como const StudentT. Entonces cuando intenta llamar al getId() con el objeto const, el compilador detecta un problema, es decir, llama a una función miembro no const en el objeto const que no está permitido porque las funciones miembro no constantes NO HACEN NINGUNA PROMESA para no modificar el objeto; entonces el compilador hará una suposición segura suponiendo que getId() podría intentar modificar el objeto pero al mismo tiempo, también nota que el objeto es const; por lo que cualquier intento de modificar el objeto const debería ser un error. Por lo tanto, el compilador genera un mensaje de error.

La solución es simple: hacer las funciones const como:

int getId() const { 
    return id; 
} 
string getName() const { 
    return name; 
} 

Esto es necesario porque ahora se puede llamar getId() y getName() en objetos const como:

void f(const StudentT & s) 
{ 
    cout << s.getId(); //now okay, but error with your versions 
    cout << s.getName(); //now okay, but error with your versions 
} 

Como comentario, se debe implementar operator< como:

inline bool operator< (const StudentT & s1, const StudentT & s2) 
{ 
    return s1.getId() < s2.getId(); 
} 

Los parámetros de nota ahora son const de referencia.

+1

Una explicación tan clara. Gracias. Pero me pregunto acerca de su último fragmento de código. ¿Por qué usar referencia en el parámetro de función? 'const StudentT & s1, const StudentT & s2'? –

+0

@RafaelAdel: Utiliza la referencia para evitar la copia innecesaria, y 'const' porque la función no necesita modificar el objeto, por lo que' const' impone esto en tiempo de compilación. – Nawaz

62

Las funciones miembro que no modifican la instancia de clase deben ser declarados como const:

int getId() const { 
    return id; 
} 
string getName() const { 
    return name; 
} 

Cada vez que vea "descarta calificadores", se está hablando de const o volatile.

+2

@Fred - ¿Creen que es definitivamente un requisito agregar modificadores const a las funciones miembro que no modifican la instancia de la clase? ¿Hay alguna otra razón para el error en este caso? Lo dudo porque en la mayoría de los getters que escribo, no le agrego modificadores de const. – Mahesh

+0

@Fred - http://ideone.com/WXr9z – Mahesh

+0

@Mahesh: Sí, es parte de [const correctness] (http://www.parashift.com/c++faq-lite/const-correctness.html). No estoy seguro de dónde viene el 'const', pero sospecho que el' set' devuelve una referencia constante del iterador para evitar que la instancia cambie y, por lo tanto, invalidar el conjunto. –

3

En realidad, el C++ estándar (es decir, C++ 0x draft) dice (TNX a @Xeo & @Ben Voigt por señalarlo a mí):

23.2.4 Associative containers
5 For set and multiset the value type is the same as the key type. For map and multimap it is equal to pair. Keys in an associative container are immutable.
6 iterator of an associative container is of the bidirectional iterator category. For associative containers where the value type is the same as the key type, both iterator and const_iterator are constant iterators. It is unspecified whether or not iterator and const_iterator are the same type.

Así VC++ 2008 Dinkumware aplicación es defectuosa.


vieja respuesta:

Tienes que el error debido a que en ciertas implementaciones de la std lib El set::iterator es lo mismo que set::const_iterator.

Por ejemplo libstdC++ (incluido con g ++) ha (véase here para todo el código fuente):

typedef typename _Rep_type::const_iterator   iterator; 
typedef typename _Rep_type::const_iterator   const_iterator; 

Y en docs de SGI se afirma:

iterator  Container Iterator used to iterate through a set. 
const_iterator Container Const iterator used to iterate through a set. (Iterator and const_iterator are the same type.) 

Por otro VC mano ++ 2008 Express compila su código sin quejarse de que está llamando a métodos no const en set::iterator s.

Cuestiones relacionadas