Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

enable_if compilation question void = nullptr

Tags:

c++

Does anyone know why assigning type* = 0 doesn't work, while type* = nullptr does? In both cases typedef void type. Thanks

#include <type_traits>
#include <iostream>

template <class T,
      typename std::enable_if<std::is_integral<T>::value>::type* = 0>
void do_stuff(T& t) {
    std::cout << "do_stuff integral\n";
}

#if 0 // works
template <class T,
      typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
void do_stuff(T& t) {
    std::cout << "do_stuff integral\n";
}
#endif


struct S {};
int main(int argc, char *argv[])
{
    int i = 1;
    do_stuff(i);
    return 0;
}

Compilation:

clang++ -pedantic -Wall -std=c++11 test190.cc && ./a.out
test190.cc:23:5: error: no matching function for call to 'do_stuff'
    do_stuff(i);
    ^~~~~~~~
test190.cc:6:6: note: candidate template ignored: substitution failure
      [with T = int]: null non-type template argument must be cast to template
      parameter type 'typename
      std::enable_if<std::is_integral<int>::value>::type *' (aka 'void *')
void do_stuff(T& t) {
     ^
1 error generated.
like image 828
notaorb Avatar asked Jul 22 '20 03:07

notaorb


2 Answers

Technically speaking, this is because a non-type template argument must be a "converted constant expression" of the parameter type. This means that the argument itself must be a constant expression, and its conversion to the required parameter type must use only the conversions specified in [expr.const]/4.

According to [expr.const]/4, null pointer conversions are only allowed from std::nullptr_t. In other words, the conversion from 0 to a null pointer value is not allowed as part of the implicit conversion sequence in a converted constant expression.

Yet it's perfectly legitimate to specify static_cast<T*>(0) as a template argument to a non-type template parameter of type T*. In other words, a null pointer conversion from 0 is allowed as part of a constant expression. It's only when the conversion is done at a certain point---after computing the argument and while converting the argument type to the parameter type---that the standard forbids it.

I have no idea about the rationale for this rule.

like image 116
Brian Bi Avatar answered Nov 13 '22 03:11

Brian Bi


** nullptr and 0 are not the same. **

For a very clear explanation please see the following:

https://hackernoon.com/what-exactly-is-nullptr-in-c-94d63y6t

@brian has provided a very good technical answer, but I felt it necessary to add this answer since we should no longer be trying to use 0 for pointer values.

like image 41
Geoff Avatar answered Nov 13 '22 01:11

Geoff