c++ templates language-lawyer void-pointers nullptr

c++ - ¿Por qué `void*= 0` y` void*= nullptr` hacen la diferencia?



templates language-lawyer (1)

Los argumentos de plantilla predeterminados siguen sus propias reglas de conversión, que son más estrictas. La conversión de 0 a un tipo de puntero en particular, no se aplica.

Ver [temp.arg.nontype]/5.2 (énfasis mío):

para un parámetro-plantilla no tipo de tipo puntero a objeto, se aplican las conversiones de calificación ([conv.qual]) y la conversión de matriz a puntero ([conv.array]); si la plantilla-argumento es de tipo std::nullptr_t , se std::nullptr_t la conversión de puntero nulo ([conv.ptr]).

[ Nota: En particular, ni la conversión de puntero nulo para una expresión de constante integral de valor cero ([conv.ptr]) ni la conversión derivada a base ([conv.ptr]) se aplican. Aunque 0 es un argumento de plantilla válido para un parámetro de plantilla de tipo integral que no es de tipo, no es un argumento de plantilla válido para un parámetro de plantilla de tipo puntero que no es de tipo. Sin embargo, tanto (int*)0 como nullptr son argumentos de plantilla válidos para un parámetro de plantilla no tipo de tipo "puntero a int." - nota final]

Estaba jugando con SFINAE y encontré un comportamiento que no puedo explicar.

Esto compila bien :

template<typename Integer, std::enable_if_t<std::is_integral<Integer>::value>* = nullptr> void foo(Integer) {} template<typename Floating, std::enable_if_t<std::is_floating_point<Floating>::value>* = nullptr> void foo(Floating) {}

Mientras esto ( nullptr reemplazado con 0 ):

template<typename Integer, std::enable_if_t<std::is_integral<Integer>::value>* = 0> void foo(Integer) {} template<typename Floating, std::enable_if_t<std::is_floating_point<Floating>::value>* = 0> void foo(Floating) {}

me da un error de compilación

prog.cpp: In function ‘int main()’: prog.cpp:13:10: error: no matching function for call to ‘foo(int)’ foo(3); ^ prog.cpp:5:6: note: candidate: template<class Integer, std::enable_if_t<std::is_integral<_Tp>::value>* <anonymous> > void foo(Integer) void foo(Integer) {} ^~~ prog.cpp:5:6: note: template argument deduction/substitution failed: prog.cpp:4:64: error: could not convert template argument ‘0’ to ‘std::enable_if_t<true, void>* {aka void*}’ std::enable_if_t<std::is_integral<Integer>::value>* = 0> ^ prog.cpp:9:6: note: candidate: template<class Floating, std::enable_if_t<std::is_floating_point<_Tp>::value>* <anonymous> > void foo(Floating) void foo(Floating) {} ^~~ prog.cpp:9:6: note: template argument deduction/substitution failed: prog.cpp:8:71: note: invalid template non-type parameter std::enable_if_t<std::is_floating_point<Floating>::value>* = 0> ^

enable_if_t expande para void cuando no hay fallas de sustitución, así que tendré algo como void* = 0 en la lista de parámetros de la plantilla. ¿Por qué se rompe la compilación? ..