web-dev-qa-db-ja.com

なぜ `void * = 0`と` void * = nullptr`が違いを生むのですか?

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

この間(nullptr0に置き換えられました):

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

コンパイルエラーを表示します

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_tvoidに展開されるため、テンプレートパラメータのリストの中にvoid* = 0のようなものがあります。なぜコンパイルが壊れるのですか?.

22
Mikhail

デフォルトのテンプレート引数は、より厳密な独自の変換規則に従います。特に0からポインタ型への変換は適用されません。

[temp.arg.nontype] /5.2 (私の強調)を参照してください。

オブジェクトへのタイプポインターの非タイプテンプレートパラメーターの場合、修飾変換([conv.qual])と配列からポインターへの変換([conv.array])が適用されます。テンプレート引数のタイプがstd::nullptr_tの場合、ヌルポインター変換([conv.ptr])が適用されます。

[注:特に、ゼロ値の積分定数式([conv.ptr])のnullポインター変換も、派生からベースへの変換([conv。 ptr])が適用されます。 0は、整数型の非タイプテンプレートパラメータの有効なテンプレート引数ですが、非タイプテンプレートパラメータの有効なテンプレート引数ではありませんポインタ型。ただし、(int*)0nullptrはどちらも、「pointer to int」型の非型テンプレートパラメータの有効なテンプレート引数です。 —エンドノート]

32
rustyx