为什么`void * = 0`和`void * = nullptr`会有所不同?

时间:2018-06-08 17:28:18

标签: c++ templates language-lawyer void-pointers nullptr

我正在玩SFINAE并发现我无法解释的行为。

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

虽然这个(nullptr替换为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会扩展为void,因此我会在模板参数列表中添加void* = 0之类的内容。为什么它会破坏编译?..

1 个答案:

答案 0 :(得分:32)

默认模板参数遵循自己的转换规则,这些规则更严格。 0转换为指针类型。

[temp.arg.nontype]/5.2(强调我的):

  

表示对象类型指针的非类型模板参数,限定转换([conv.qual])和数组到指针转换([conv.array]);如果template-argument的类型为std::nullptr_t,则应用空指针转换([conv.ptr])。

     

[注意:特别是零值整数常量表达式([conv.ptr])的空指针转换和派生到基础的转换([conv.ptr]) )应用。 虽然0是整数类型的非类型模板参数的有效模板参数,但它不是指针类型的非类型模板参数的有效模板参数。但是,(int*)0nullptr都是类型为“指向int的指针”的非类型模板参数的有效模板参数。 - 结束注释]