¿Por qué 'void * = 0' y` void* = nullptr ' marcan la diferencia?


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 que esto (nullptr sustituido por 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 se expande a void cuando no hay errores de sustitución, por lo que tendré algo como void* = 0 entre la lista de parámetros de la plantilla. ¿Por qué rompe la compilación?..

Author: Killzone Kid, 2018-06-08

1 answers

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.

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

Para una plantilla sin tipo-parámetro de tipo puntero a objeto, conversiones de calificación ([conv.qual]) y la conversión de matriz a puntero ([conv.array]); si el argumento template es de tipo std::nullptr_t, la conversión de puntero nulo ([conv.ptr]) es aplicar.

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

 30
Author: rustyx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-08 17:55:37