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
, sestd::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
comonullptr
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) {}
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? ..