Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why `void* = 0` and `void* = nullptr` makes the difference?

I was playing with SFINAE and found behavior I cannot explain.

This compiles fine:

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) {}

While this (nullptr replaced with 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) {}

gives me a compile error:

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 expands to void when there are no substitution failures, so I will have something like void* = 0 among the list of template parameters. Why does it break compilation?..

like image 367
Mikhail Avatar asked Jun 08 '18 17:06

Mikhail


People also ask

Can void * Be nullptr?

Nullptr cannot be defined as (void*)0 in the C++ standard library. Null pointer is a subtle example of Return Type Resolver idiom to automatically deduce a null pointer of the correct type depending upon the type it is assigning to.

What does void *) 0 represent?

(void*)0 is a null pointer constant, whose value is a null pointer of type void* , so by the semantics of parenthesized expressions ((void*)0) also has a value that is a null pointer of type void* .

Is nullptr better than null?

As a reminder, since C++11, NULL can be either an integer literal with value zero, or a prvalue of type std::nullptr_t . Because of this ambiguity, I recommend switching exclusively to nullptr . nullptr will make your code less error-prone than relying on the implementation-defined NULL .

How null pointer is different from void pointer?

The null pointer is basically used in a program to assign the value 0 to a pointer variable of any data type. The void pointer, on the other hand, has no value assigned to it and we use it to store the addresses of other variables in the program- irrespective of their data types.


1 Answers

Default template arguments follow their own conversion rules, which are stricter. Conversion of 0 to a pointer type in particular, is not applied.

See [temp.arg.nontype]/5.2 (emphasis mine):

for a non-type template-parameter of type pointer to object, qualification conversions ([conv.qual]) and the array-to-pointer conversion ([conv.array]) are applied; if the template-argument is of type std::nullptr_t, the null pointer conversion ([conv.ptr]) is applied.

[ Note: In particular, neither the null pointer conversion for a zero-valued integral constant expression ([conv.ptr]) nor the derived-to-base conversion ([conv.ptr]) are applied. Although 0 is a valid template-argument for a non-type template-parameter of integral type, it is not a valid template-argument for a non-type template-parameter of pointer type. However, both (int*)0 and nullptr are valid template-arguments for a non-type template-parameter of type “pointer to int.” — end note ]

like image 51
rustyx Avatar answered Sep 17 '22 14:09

rustyx