Conversión de expresión constante constante a puntero nulo

Considere el siguiente código:

#include  void f( std::shared_ptr ) {} int main() { f( 0 ); // compiles fine in gcc and clang f( 1 - 1 ); // compiles fine in gcc, fails in clang constexpr int i = 0; f( i ); // fails to compile in gcc and clang f( i - 0 ); // compiles fine in gcc, fails in clang } 

¿por qué solo f( i ) no comstack, aunque debería evaluarse como constante de tiempo de comstackción con valor 0?

PS verificado con g ++ v 5.1.0, acepta todas las variantes excepto f(i); tanto en el modo PPS c ++ 11 como en el modo c ++ 14 verificado con el Clang 3.7, rechaza todas las variantes excepto el literal 0 en el modo c ++ 11 y c ++ 14

Este es un error gcc. Informe de defectos 903: constantes de puntero nulo integrales dependientes del valor, que es un informe de defectos contra C ++ 11 ( tiene estado de CD3 ), por lo que solo un literal 0 entero se considera una constante de puntero nulo.

Cambió la sección 4.10 [conv.ptr] párrafo 1 entre otros cambios de:

Una constante de puntero nula es una expresión constante constante (5.19 [expr.const]) prvalue de tipo entero que se evalúa a cero […]

a:

Una constante de puntero nula es un literal entero (2.14.2 [lex.icon]) con valor cero […]

Esto se enumera como una incompatibilidad contra C ++ 03, de la sección C.2.2 Cláusula 4: conversiones estándar [diff.cpp03.conv] que dice:

Cambio: Sólo los literales son constantes de puntero nulo enteros
Justificación: Eliminar interacciones sorprendentes con plantillas y expresiones constantes.
Efecto en la característica original: el código válido de C ++ 2003 puede fallar al comstackr o producir resultados diferentes en esta Norma Internacional, como lo ilustra el siguiente ejemplo:

 void f(void *); // #1 void f(...); // #2 template void g() { f(0*N); // calls #2; used to call #1 } 

El siguiente informe de error de gcc [C ++ 11] [DR 903] la expresión constante de entero de valor cero debería preferir la conversión al puntero muestra que el equipo de gcc originalmente pensó que era un cambio de C ++ 17, pero luego lo modificó para que esté vigente en C ++ 11.

Podemos ver en la revisión principal de gcc ( 6.0 ) que esto está arreglado ( verlo en vivo ) y produce un diagnóstico para todos los casos que hace el clang:

 error: could not convert '(1 - 1)' from 'int' to 'std::shared_ptr' f( 1 - 1 ); // compiles fine in gcc, fails in clang ~~^~~ error: could not convert 'i' from 'const int' to 'std::shared_ptr' f( i ); // fails to compile in gcc and clang ^ error: could not convert '(0 - 0)' from 'int' to 'std::shared_ptr' f( i - 0 ); // compiles fine in gcc, fails in clang ~~^~~ 

Debido a que una constante de puntero nulo se define no solo como una constante integral de comstackción con valor 0, sino como un literal entero con valor cero (o como un prvalor de tipo std::nullptr_t , por supuesto). C ++ 14 (N4140), 4.10 / 1.

Entonces, en realidad, solo la primera línea f(0) debe comstackrse, todas las demás deben provocar al menos un mensaje de diagnóstico de un comstackdor conforme.