¿Por qué un valor de una enumeración con un tipo subyacente fijo de char se resuelve en fct(int) en lugar de fct(char)?


Este problema surgió al responder esta pregunta sobre la resolución de sobrecarga con enums.

Mientras que el caso de long long fue definitivamente un error en MSVC2012NovCTP (de acuerdo con el texto estándar y una prueba con gcc 4.7.1), no puedo entender por qué ocurre el siguiente comportamiento:

#include <iostream>

enum charEnum : char { A = 'A' };

void fct(char)      { std::cout << "fct(char)"      << std::endl; }
void fct(int)       { std::cout << "fct(int)"       << std::endl; }
void fct(long long) { std::cout << "fct(long long)" << std::endl; }

int main() 
{
    fct('A');
    fct(A);
}

Tanto MSVC2012NovCTP como gcc 4.7.1 están de acuerdo en esta salida:

Fct (char)
fct (int)

No debería {[2] } convertirse de charEnum a char? ¿Por qué se está convirtiendo A a int?

EDIT: clang se queja de que la llamada es ambigua, lo que concuerda con mi interpretación a continuación; dicho esto, todavía lo encontraría mucho más intuitivo si solo se considerara como el tipo subyacente.


Dos extractos estándar relevantes son §7.2 / 9:

El valor de un enumerador o un objeto de un tipo de enumeración sin ámbito se convierte en un entero por promoción integral (4.5)

Y §4.5/4:

Un prvalue de un tipo de enumeración sin ámbito cuyo tipo subyacente es fijo (7.2) se puede convertir en un prvalue de su tipo subyacente. Además, si la promoción integral se puede aplicar a su tipo subyacente, un prvalue de un tipo de enumeración sin ámbito cuyo tipo subyacente es fijo también se puede convertir en un prvalue del tipo subyacente promovido.

Así que charEnum puede ser convertido a char, o cualquier promoción integral de char, tales como int.

Pero esto es vago para mí porque "puede" no dice exactamente cuál será realmente elegido. En todo caso, esto debe ser ambiguo con esta redacción porque no se da preferencia entre char o cualquiera de sus promociones. Si comentas fct(int), entonces la llamada es ambigua. ¿Por qué es especial int?

Lo único que se me ocurre es que las promociones integrales se aplican recursivamente, pero nada de lo que veo lo obliga.

Author: Community, 2013-01-08

2 answers

En C++03, la regla era:

Un rvalue de un tipo de enumeración sin ámbito (7.2 [dcl.enum]) puede ser convertido a un rvalue del primero de los siguientes tipos que puede representar todos los valores de la enumeración (es decir, los valores en el range bmin to bmax as described in 7.2 [dcl.enum]): int, unsigned int, long int, unsigned long int, long long int o unsigned long long int.

En un compilador C++03, int se elegiría porque es el primero en el lista.


En C++11, se introdujo el tipo subyacente . En consecuencia, via 685. La promoción integral de la enumeración ignora el tipo subyacente fijo , esta redacción se cambió al párrafo que citó en §4.5/4 y de la lectura del informe de defectos, parece que la intención del comité era elegir fct(char) (el tipo subyacente).

Sin embargo, de acuerdo con la discusión bajo core issue 1601, el texto en C++11 en realidad hace que la conversión ambigua (fct(char) y fct(int) son posibles y no se prefiere ninguna).

La siguiente corrección fue propuesta y aceptada en C++14:

Una conversión que promueve una enumeración cuyo tipo subyacente es fijo su tipo subyacente es mejor que uno que promueve la tipo subyacente promovido, si los dos son diferentes.

Dado que se informó como un defecto en C++11, los compiladores deberían aplicar esta corrección cuando estén en modo C++11 y llamar a fct(char).

 9
Author: Jesse Good,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-12 02:16:32

Según mi interpretación del estándar actual, la llamada tiene que ser ambigua. Sigue una explicación.

Por 4,5 / 4:

"Un prvalue de un tipo de enumeración sin ámbito cuyo tipo subyacente es fijo (7.2) se puede convertir en un prvalue de su tipo subyacente. Además, si la promoción integral se puede aplicar a su tipo subyacente, un prvalue de un tipo de enumeración sin ámbito cuyo tipo subyacente es fijo también se puede convertir en un prvalue del promovido tipo subyacente."

Esto ofrece dos alternativas promociones: una promoción al tipo subyacente, y una promoción al tipo subyacente promovido. Por lo tanto, este párrafo por sí solo introduce ambigüedad en cuanto a que de estas alternativas deben usarse al resolver una llamada a una función a funciones sobrecargadas.

A continuación, el punto 13.3.3 decide cuál es la función más viable de un conjunto de sobrecarga en términos de "secuencia de conversión". En particularmente, relevante para este asunto es 13.3.3.1 ("Secuencias de conversión implícitas") y, más específicamente, 13.3.3.1.1 ("Secuencias de conversión estándar"), que define de qué pasos elementales están hechas estas secuencias de conversión.

13.3.3.1.1/1 y la Tabla 12 clasifican estos pasos en cuatro categorías, entre las cuales Promoción y Conversión, y clasifican las secuencias de conversión en función de la categoría de conversiones individuales que componen esas secuencias.

En nuestro caso, tenemos dos secuencias de conversión de una sola longitud compuestas por una sola Promoción paso (ambos permitidos por 4.5./4).

Las secuencias de conversión se clasifican de acuerdo con 13.3.3.2. En particular, 13.3.3.2 / 3 menciona que una secuencia de conversión S1 es preferible a una secuencia de conversión S2 si:

"el rango [es decir, Promoción, Conversión, etc.] S1 es mejor que el rango de S2 o S1 y S2 tienen el mismo rango y sean distinguibles por las reglas que figuran en el párrafo siguiente, o, de no ser así, [...]"

El" párrafo siguiente " que se menciona es 13.3.3.2 / 4, que dice:

"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:"

Entonces, lo que sigue es un conjunto de reglas que no se aplican en nuestra situación.

Por lo tanto, tenemos dos secuencias de conversión de un solo paso compuestas por una única Promoción con el mismo rango. De acuerdo con la interpretación anterior del estándar actual, la llamada tiene que ser ambigua.

Personalmente, sin embargo, estoy de acuerdo en que se necesita un cambio para que la conversión al tipo subyacente fijo de una enumeración sin ámbito sea preferible a otras conversiones posibles.

 3
Author: Andy Prowl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-08 21:22:55