2011-06-29 19 views
6

siguiente es el código de prueba:¿Por qué la versión no const se selecciona sobre la versión const para la clase?

struct A 
{ 
    operator int(); 
    operator int() const; 
}; 

void foo (const int); 

Ahora, al invocar:

foo(A()); // calls A::operator int() 

¿Por qué se always chooses the non-const version? Incluso hacer operator const int() const; no tiene ningún efecto al invocar foo(). Además de la referencia estándar, ¿alguien puede explicar lógicamente, la razón detrás de esto?

Respuesta

13

A() le ofrece un objeto temporal A que no es const-calificado. La expresión A() es una expresión rvalue, sí, pero eso no hace que el objeto A const-qualified.

Puesto que el objeto A no es const-calificado, la no const operator int() es una coincidencia exacta y la const operator int() requiere una conversión calificación, por lo que la sobrecarga no constante se selecciona como la mejor coincidencia.

Si usted quiere que sea const cualificado, que había necesidad de solicitar explícitamente una constante cualificado A:

foo(identity<const A>::type()); 

donde identity se define como

template <typename T> 
struct identity { typedef T type; }; 

en cuenta que hay realmente no hay diferencia entre operator const int() const y operator int() const: el resultado es un valor r y solo los valores de clase pueden ser const-qualified (int no es un tipo de clase).

Tenga en cuenta también que no hay diferencia entre el void foo(const int) que tiene y el void foo(int). Los calificadores const de nivel superior en los tipos de parámetros no afectan el tipo de la función (es decir, el tipo de ambas declaraciones es void foo(int)). Entre otras razones, esto se debe a que no le importa a la persona que llama si hay un clasificador const de nivel superior; tiene que hacer una copia independientemente. El calificador const de nivel superior afecta solo a la definición de la función.

+0

Incluso 'A' ser una pila/montón asignado objeto normal (no temporal), da el mismo resultado. – iammilind

+0

Si el objeto no está const-calificado, la sobrecarga sin const es una mejor coincidencia durante la resolución de sobrecarga. ¿Hay alguna razón por la que esperas que este no sea el caso? –

+0

Por qué me confundo es, incluso si 'foo()' recibe 'const int' y tenemos un' A :: operator const int() const; ', aún así va y elige el operador' A :: virtual int 'normal . – iammilind

4

Una regla que debe recordar acerca de C++: es nunca tiene en cuenta el valor que se devuelve cuando selecciona una sobrecarga. En este caso, dado que la función operator int no toma parámetros, tampoco puede usar la lista de parámetros para restringir las opciones. Todo lo que puede usar es la consistencia del objeto desde el que se llama. Dado que este es un nuevo objeto temporal, no es const, por lo que no elige la sobrecarga const.

+1

* Nunca * es quizás demasiado fuerte; el tipo de devolución se tiene en cuenta cuando se resuelve la sobrecarga cuando se toma la dirección de una función y cuando se resuelven los operadores de conversión para una conversión automática. (Esto último puede ser muy útil cuando se desea tener una función sobrecargada en el tipo de retorno. Hacer que devuelva un proxy con diferentes operadores de conversión.) –

5

James McNellis ’ respuesta realmente lo cubrió todo, pero no lo hace ’ lastimado (espero) con más explicaciones.

So.

Cuando llamas & hellip;

o.operator int() 

& hellip; entonces la selección de sobrecarga depende completamente de constness de o.

Nada más.

Para ver por qué, consideremos esta clase:

struct Bar 
{ 
    void f() {} 
    void f() const {} 
}; 

Técnicamente estas funciones miembro no necesitan ser funciones miembro. Podrían haber sido elegidos para funciones autónomas. Pero entonces necesitan Bar argumento:

struct Bar 
{}; 

void f(Bar&) {} 
void f(Bar const&) {} 

Y es de esperar ahora es más fácil ver que cuando se hace

Bar o; 
f(o); 

entonces la primera función puede ser seleccionado. Y así es. Porque si se seleccionó la segunda función, nunca se podría obtener la primera. Porque si crea el objeto const, rompería la corrección de const para seleccionar el primero. Entonces, cuando el objeto es const, solo se puede seleccionar el segundo, por lo tanto, cuando no es const, se selecciona el primero.

En resumen, la única alternativa práctica a esta regla sería seleccionar siempre la segunda, lo que haría que la primera sea bastante inútil, ¿sí?

Saludos & hth.,

+0

Si la versión no const se hace privada, aún trata de usar esa en lugar de la versión pública const, con el consiguiente error de "intentar acceder a un miembro privado". Muy molesto. – Oktalist

Cuestiones relacionadas