c++ - ¿Por qué esta función de asignación de punteros funciona cuando se asigna directamente pero no con el operador condicional?
function pointers (3)
En el primer caso, el compilador se resiste incluso antes de llegar a la tarea. Una expresión simplificada:
(true ? std::toupper : std::tolower)
No se compilará si hay varias sobrecargas de
toupper
/
tolower
presente.
Esto se debe a que el tipo de retorno del operador ternario debe establecerse basándose únicamente en los tipos de segundo y tercer argumento, sin mirar nunca el contexto donde se utiliza el resultado.
Lo suficientemente divertido, incluso si uno de esos argumentos no es una función sobrecargada, todavía no es suficiente. Las razones para ello son menos obvias y tienen más que ver con las reglas de resolución de sobrecarga 1 y dónde se aplican. Un lanzamiento es precisamente una de las siete posibilidades para activarlo, y la determinación del tipo de destino de los operadores ternarios en sí no lo es.
En el caso de la asignación directa, los rhs de asignación deben ajustarse a las lhs, por lo que no hay ambigüedad.
De cualquier manera , según lo señalado por @Caleth, de acuerdo con 16.5.4.2.1.6 , este código tiene un comportamiento no especificado.
1 La referencia de C ++ tiene un párrafo estándar de C ++ incorrecto. [over.over] es en realidad 12.4.
(No se utilizaron # include para este ejemplo, compilado en MacOS10.14, Eclipse IDE, con g ++, opciones -O0 -g3 -Wall -c -fmessage-length = 0)
Suponiendo esta declaración de variable:
int (*fun)(int);
Esto no se compila con "sobrecarga no válida de std :: toupper y std :: tolower".
fun = (1 ? std::toupper : std::tolower); // ERROR, invalid overload
Y esto compila OK:
if (1) {
fun = std::toupper; // OK
}
else {
fun = std::tolower; // OK
}
Este snippet compila muy bien con gcc 9.1
#include <cctype>
int chr2fun(bool str2modus) {
const bool STR2UP = true;
int (*chr2fun)(int);
if (str2modus == STR2UP) {
chr2fun = std::toupper;
} else {
chr2fun = std::tolower;
}
chr2fun = (str2modus == STR2UP ? std::toupper : std::tolower);
}
¿En qué plataforma y con qué compilador recibe el error?
std::toupper
(
1
y
2
) y
std::tolower
(
1
y
2
) están sobrecargados.
Cuando se determina el tipo común entre ellos para el
operador condicional
(antes de la asignación a
chr2fun
), no se puede determinar qué sobrecarga se debe usar.
Puede usar
static_cast
para especificar cuál debe ser considerado.
(Presuntamente, para forzar la
resolución de sobrecarga
ocurre al principio, respectivamente, luego desaparece el problema para determinar el tipo común).
static_cast
también se puede usar para desambiguar las sobrecargas de funciones al realizar una conversión de función a puntero a un tipo específico
p.ej
chr2fun = (str2modus == STR2UP ? static_cast<int(*)(int)>(std::toupper)
: static_cast<int(*)(int)>(std::tolower));
Para el segundo caso,
chr2fun
se asigna directamente;
el tipo de
chr2fun
es explícito y la sobrecarga correcta se seleccionaría en la
resolución de sobrecarga
.
(énfasis mío)
En todos estos contextos, la función seleccionada del conjunto de sobrecarga es la función cuyo tipo coincide con el puntero a la función, la referencia a la función o el puntero al tipo de función miembro que espera el objetivo: el objeto o la referencia que se está inicializando, la parte izquierda lado de la asignación , función o parámetro de operador, el tipo de retorno de una función, el tipo de destino de una conversión o el tipo de parámetro de la plantilla, respectivamente.