c++ - lenguaje - punteros y matrices en c
¿Por qué el puntero a int se convierte a void*pero el puntero a la función convierte a bool? (1)
En función de lo anterior, está perfectamente bien convertir un puntero de función o un puntero a un
int
avoid*
y tambiénbool
.
La cita indica que un puntero a un objeto se puede convertir a cv void *
. Las funciones no son objetos, y esto descalifica la conversión a cv void *
, dejando solo bool
.
Sin embargo, dada la elección de ambos, ¿a cuál se debe convertir un puntero?
Debe convertir a const void *
over bool
. ¿Por qué? Bien, prepárese para un viaje que comienza en Resolución de Sobrecarga (§13.3 [over.match] / 2). Énfasis mío, por supuesto.
Pero, una vez que las funciones candidatas y las listas de argumentos han sido identificadas, la selección de la mejor función es la misma en todos los casos:
- En primer lugar, se selecciona un subconjunto de las funciones candidatas (aquellas que tienen el número adecuado de argumentos y cumplen ciertas otras condiciones) para formar un conjunto de funciones viables (13.3.2).
- Entonces, la mejor función viable se selecciona en función de las secuencias de conversión implícitas (13.3.3.1) necesarias para unir cada argumento con el parámetro correspondiente de cada función viable.
Entonces, ¿qué hay de estas secuencias de conversión implícitas?
Pasemos a §13.3.3.1 [over.best.ics] / 3 y veamos qué es una secuencia de conversión implícita:
Una secuencia de conversión implícita bien formada es una de las siguientes formas:
- una secuencia de conversión estándar (13.3.3.1.1),
- una secuencia de conversión definida por el usuario (13.3.3.1.2), o
- una secuencia de conversión de puntos suspensivos (13.3.3.1.3).
Estamos interesados en las secuencias de conversiones estándar. Pasemos a las Secuencias de conversión estándar (§13.3.3.1.1 [over.ics.scs]):
1 La Tabla 12 resume las conversiones definidas en la Cláusula 4 y las divide en cuatro categorías disjuntas: Transformación de Lvalue, Ajuste de Calificación, Promoción y Conversión. [Nota: Estas categorías son ortogonales con respecto a la categoría de valor, calificación cv y representación de datos: las Transformaciones Lvalue no cambian la calificación cv o la representación de datos del tipo; los Ajustes de Calificación no cambian la categoría de valor o la representación de datos del tipo; y las Promociones y Conversiones no cambian la categoría de valor o la calificación cv del tipo. - nota final]
2 [Nota: como se describe en la cláusula 4, una secuencia de conversión estándar es la conversión de identidad en sí misma (es decir, no hay conversión) o consiste en una a tres conversiones de las otras cuatro categorías.
La parte importante es en / 2. Se permite que una secuencia de conversión estándar sea una única conversión estándar. Estas conversiones estándar se enumeran en la Tabla 12, que se muestra a continuación. Observe que tanto sus Conversiones de puntero como las Conversiones booleanas están ahí.
A partir de aquí, aprendemos algo importante: las conversiones de puntero y las conversiones booleanas tienen el mismo rango. Recuerde que a medida que nos dirigimos a la Clasificación de Secuencias de Conversión Implícita (§13.3.3.2 [over.ics.rank]).
Mirando / 4, vemos:
Las secuencias de conversión estándar están ordenadas por sus rangos: una coincidencia exacta es una mejor conversión que una promoción, que es una mejor conversión que una conversión. Dos secuencias de conversión con el mismo rango son indistinguibles a menos que se aplique una de las siguientes reglas:
- Una conversión que no convierte un puntero, un puntero a miembro o std :: nullptr_t bool es mejor que una que sí lo hace.
Hemos encontrado nuestra respuesta en forma de una declaración muy explícita. ¡Hurra!
El Estándar de Borrador C ++ (N3337) tiene lo siguiente acerca de la conversión de punteros:
4.10 Conversiones de punteros
2 Un valor de tipo "puntero a cv
T
", dondeT
es un tipo de objeto, se puede convertir a un valor r de tipo "puntero a cvvoid
". El resultado de convertir un "puntero a cvT
" en un "puntero a cvvoid
"señala el inicio de la ubicación de almacenamiento donde reside el objeto de tipoT
, como si el objeto fuera el objeto más derivado (1.8) de tipoT
(es decir, no un subobjeto de clase base).
y
4.12 conversiones booleanas
1 Un valor de aritmética, enumeración, puntero o puntero a tipo de miembro se puede convertir a un valor r de tipo
bool
. Un valor cero, un valor de puntero nulo o un valor de puntero de miembro nulo se convierte en falso; cualquier otro valor se convierte en verdadero
En función de lo anterior, está perfectamente bien convertir un puntero de función o un puntero a un int
a void*
y también bool
.
Sin embargo, dada la elección de ambos, ¿a cuál se debe convertir un puntero?
Y luego, ¿por qué un puntero a una función se convierte a un bool
y un puntero a un int
convert a un void*
?
Programa:
#include <iostream>
using namespace std;
void foo(const void* ptr)
{
std::cout << "In foo(void*)" << std::endl;
}
void foo(bool b)
{
std::cout << "In foo(bool)" << std::endl;
}
void bar()
{
}
int main()
{
int i = 0;
foo(&bar);
foo(&i);
return 0;
}
Salida, usando g ++ 4.7.3:
In foo(bool) In foo(void*)