tutorialspoint pointer ejemplo c++ pointers c++11 null-pointer

pointer - ¿Por qué compila "bool c=nullptr;"(C++ 11)?



pointers c++ (4)

No entiendo por qué el siguiente código compiles ?

int main() { //int a = nullptr; // Doesn''t Compile //char b = nullptr; // Doesn''t Compile bool c = nullptr; // Compiles return 0; }

mientras que la sección comentada no lo hace.

Ya he pasado por this y this .

Tanto bool como nullptr son palabras clave, entonces, ¿qué tiene de especial los otros tipos de datos?


C ++ 11 §4.12 conversiones booleanas

Un prvalor de enumeración aritmética, sin cobertura, puntero o puntero a tipo de miembro se puede convertir a un prvalue de tipo bool . Un valor cero, un valor de puntero nulo o un valor de puntero de miembro nulo se convierte en false ; cualquier otro valor se convierte en true . Un prvalue de tipo std::nullptr_t se puede convertir a un prvalue de tipo bool ; el valor resultante es false .

Es cierto que nullptr es una palabra clave, pero es un literal de puntero nulo, no el mismo rol que bool . Piense en los literales booleanos, true y false también son palabras clave.


C ++ 11 corrige esto al introducir una nueva palabra clave para servir como una constante de puntero nulo distinguido: nullptr. Es de tipo nullptr_t, que es implícitamente convertible y comparable a cualquier tipo de puntero o tipo de puntero a miembro. No es implícitamente convertible o comparable a los tipos integrales, a excepción de bool. Si bien la propuesta original especificaba que un valor r de tipo nullptr no debería ser convertible en bool, el grupo de trabajo del lenguaje central decidió que dicha conversión sería deseable, para mantener la coherencia con los tipos de punteros regulares. Los cambios de redacción propuestos se votaron por unanimidad en el documento de trabajo en junio de 2008. [2]

Por razones de compatibilidad con versiones anteriores, 0 sigue siendo una constante de puntero nulo válida.

char *pc = nullptr; // OK int *pi = nullptr; // OK bool b = nullptr; // OK. b is false. int i = nullptr; // error


En open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#654 , argumenta Jason Merril

Cualquier cosa que podamos hacer con un puntero arbitrario, deberíamos poder hacer con nullptr_t también.

Creo que el siguiente ejemplo (ligeramente artificial) respalda ese argumento (aunque no estoy totalmente seguro de si fue pensado para este caso)

template<typename T, typename P> void safeProcess(T pointer, P &processor) { bool isNonNull(pointer); if(isNonNull) { processor.process(pointer); } }

Lo cual permitiría pasar nullptr junto con otros tipos de punteros compatibles con cualquier processor.process acepte el proceso.


Por la misma razón que

if( p ) { ... }

compila: cualquier valor de tipo básico se convierte implícitamente a booleano, con 0 convirtiendo a false y cualquier otro valor a true .

Originalmente, los valores de tipo básicos tenían que convertirse a bool para compatibilidad con C. C originalmente no tenía un tipo de bool , pero cualquier expresión numérica se podía usar como booleano (con la convención 0 == false ). Y ahora estamos atrapados en el enredo de compatibilidad hacia atrás. nullptr tiene que soportar construcciones idiomáticas como if(p) , especialmente para los casos en que el antiguo código literal 0 o NULL se reemplaza por nullptr . Por ejemplo, un código como if(p) puede ser el resultado de una macro expansión o de un código de plantilla.

Adición : el cómo técnico de por qué nullptr no convierte a eg int .

Como nullptr convierte implícitamente a bool , y bool (desafortunadamente) convierte implícitamente a int , se podría esperar que nullptr también convierta a int . Pero el punto de nullptr es que debe comportarse como un valor de puntero . Y mientras los punteros se convierten implícitamente a bool , no se convierten implícitamente a tipos numéricos.

Disposición de tal restricción para un tipo definido por el usuario, sin embargo, no es del todo sencillo. Se invocará una conversión operator bool para la conversión a int , si está presente. Una solución de C ++ 11 para evitar la restricción es hacer que el operador de conversión sea una plantilla, restringida por std::enable_if , de la siguiente manera:

#include <type_traits> // std::enable_if, std::is_same struct S { template< class Type > operator Type* () const { return 0; } template< class Bool_type, class Enabled = typename std::enable_if< std::is_same<Bool_type, bool>::value, void >::type > operator Bool_type () const { return false; } }; auto main() -> int { bool const b = S(); // OK. double const* const p = S(); // OK. int const i = S(); // !Doesn''t compile. }