variable usar que ejemplos ejemplo definir dato como booleano bool c++ c++11 standards-compliance narrowing list-initialization

c++ - usar - Reducción de la conversión a bool en la inicialización de lista-comportamiento extraño



variable bool (1)

Considere esta pieza de código C ++ 11:

#include <iostream> struct X { X(bool arg) { std::cout << arg << ''/n''; } }; int main() { double d = 7.0; X x{d}; }

Hay una conversión de reducción de un doble a un bool en la inicialización de x . De acuerdo con mi entendimiento del estándar, este es un código mal formado y deberíamos ver algún diagnóstico.

Visual C ++ 2013 emite un error:

error C2398: Element ''1'': conversion from ''double'' to ''bool'' requires a narrowing conversion

Sin embargo, tanto Clang 3.5.0 como GCC 4.9.1, usando las siguientes opciones

-Wall -Wextra -std=c++11 -pedantic

compile este código sin errores y sin advertencias . Ejecutando el programa sale un 1 (no hay sorpresa allí).

Ahora, profundicemos en territorio extraño.

Cambie X(bool arg) a X(int arg) y, de repente, tenemos un error de Clang

error: type ''double'' cannot be narrowed to ''int'' in initializer list [-Wc++11-narrowing]

y una advertencia de GCC

warning: narrowing conversion of ''d'' from ''double'' to ''int'' inside { } [-Wnarrowing]

Esto se parece más a lo que esperaba.

Ahora, mantenga el argumento del constructor bool (es decir, vuelva a X(bool arg) ), y cambie double d = 7.0; a int d = 7; . Nuevamente, un error de estrechamiento de Clang, pero GCC no emite ningún diagnóstico y compila el código.

Hay algunas variantes de comportamiento más que podemos obtener si pasamos la constante directamente al constructor, algunas extrañas, otras esperadas, pero no las enumeraré aquí. Esta pregunta se está volviendo demasiado larga.

Yo diría que este es uno de los casos raros en los que VC ++ tiene razón y Clang y GCC están equivocados en lo que respecta a la conformidad con los estándares, pero, dados los registros respectivos de estos compiladores, sigo teniendo muchas dudas al respecto.

¿Qué piensan los expertos?

Referencias estándar (citas del documento estándar final para C ++ 11, ISO / IEC 14882-2011):

En el párrafo 3 de 8.5.4 [dcl.init.list], tenemos:

- De lo contrario, si T es un tipo de clase, los constructores son considerados. Los constructores correspondientes se enumeran y el mejor se elige mediante resolución de sobrecarga (13.3, 13.3.1.7). Si se requiere una conversión de reducción (ver más abajo) para convertir cualquiera de los argumentos, el programa no está bien formado.

En la misma sección, en el párrafo 7, tenemos:

Una conversión estrecha es una conversión implícita
- desde un tipo de punto flotante a un tipo entero, o
- de long double a double o float, o de double a float, excepto cuando la fuente es una expresión constante y el valor real después de la conversión está dentro del rango de valores que se pueden representar (incluso si no se puede representar exactamente), o
- desde un tipo entero o un tipo de enumeración sin ámbito a un tipo de punto flotante, excepto cuando el origen es una expresión constante y el valor real después de la conversión se ajustará al tipo objetivo y producirá el valor original cuando se vuelva a convertir al tipo original, o
- desde un tipo entero o un tipo de enumeración sin ámbito hasta un tipo entero que no puede representar todos los valores del tipo original, excepto cuando la fuente es una expresión constante y el valor real después de la conversión se ajustará al tipo objetivo y producirá el valor original cuando se convierte de nuevo al tipo original.
[Nota: como se indicó anteriormente, dichas conversiones no están permitidas en el nivel superior en las inicializaciones de lista. Nota final]

En 3.9.1 [basic.fundamental] párrafo 7, tenemos:

Los tipos bool, char, char16_t, char32_t, wchar_t y los tipos enteros con signo y sin signo se denominan colectivamente tipos integrales.48 Un sinónimo para tipo integral es tipo entero.

(Estaba empezando a cuestionar todo en esta etapa ...)


Esto simplemente parece un error, si intentamos lo siguiente:

bool b {3} ;

tanto gcc como clang emiten un diagnóstico, por ejemplo gcc dice:

advertencia: reducir la conversión de ''3'' de ''int'' a ''bool'' dentro de {} [-Entrada]

Esto se trata en el borrador del estándar C ++ 11 en la sección 8.5.4 , párrafo 7 de inicialización de lista, que dice:

Una conversión estrecha es una conversión implícita

[...]

  • desde un tipo entero o un tipo de enumeración sin ámbito hasta un tipo entero que no puede representar todos los valores del tipo original, excepto cuando la fuente es una expresión constante y el valor real después de la conversión se ajustará al tipo objetivo y producirá el valor original cuando convertido de nuevo al tipo original.

Este es el mismo párrafo que cubre su ejemplo y el siguiente ejemplo más simple:

bool a {3.0} ;

que estaría cubierto por este punto del párrafo 7 citado anteriormente:

  • de un tipo de punto flotante a un tipo entero, o

A partir del párrafo 3 , esto está mal formado y requiere un diagnóstico:

La inicialización de lista de un objeto o referencia de tipo T se define de la siguiente manera:

[...]

  • De lo contrario, si la lista de inicializadores tiene un solo elemento, el objeto o la referencia se inicializa desde ese elemento; Si se requiere una conversión de reducción (ver más abajo) para convertir el elemento a T, el programa no está bien formado.

el cual gcc no produce ningún diagnóstico pero clang proporciona la siguiente advertencia, aunque no la advertencia de conversión de reducción que deberíamos ver:

advertencia: la conversión implícita de ''double'' a ''bool'' cambia el valor de 3 a true [-Wliteral-conversion]

Nota, la sección 3.9.1 [basic.fundamental] dice:

Los tipos bool , char, char16_t, char32_t, wchar_t y los tipos enteros con signo y sin signo se denominan colectivamente tipos integrales .48 Un sinónimo para tipo integral es tipo entero .

Debes presentar un informe de error con clang y gcc .

Jonathan Wakely observa que el compilador de EDG produce un error de estrechamiento para el código OP, lo que es una clara indicación de que esto debería producir un diagnóstico.

Actualizar

He enviado un informe de error de gcc y clang .

El informe de errores de Clang se ha actualizado como se ha corregido :

Fijado en r229792.

El informe de error de gcc se ha actualizado como se ha corregido :

Fijo.

Y un ejemplo en vivo parece confirmar esto .