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

Mik*_*ail 22 c++ templates void-pointers nullptr language-lawyer

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

编译正常:

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) {}
Run Code Online (Sandbox Code Playgroud)

虽然这个(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) {}
Run Code Online (Sandbox Code Playgroud)

给我一个编译错误:

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>
                                                                       ^
Run Code Online (Sandbox Code Playgroud)

enable_if_t扩展到void没有替换失败的时候,所以我会void* = 0在模板参数列表中有类似的东西.为什么它会破坏编译?..

rus*_*tyx 32

默认模板参数遵循自己的转换规则,这些规则更严格.0特别是,不应用转换为指针类型.

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

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

[ 注意:特别是,既不应用零值整数常量表达式([conv.ptr])的空指针转换,也不应用派生到基本转换([conv.ptr]).虽然0对于整数类型的非类型模板参数是有效的模板参数,但它不是指针类型的非类型模板参数的有效模板参数.然而,无论是(int*)0nullptr是有效的模板参数类型的非类型模板参数"指针为int." -注完]

  • 很好找.C++有很多这样的非显而易见的规则,考虑编译器编写者必须处理的所有特殊逻辑,这是令人恐惧的. (4认同)
  • 我认为标准基本上想说"C中没有模板,所以至少*那里*我不必遵守C":) (4认同)