C++20コンセプトで導入されたrequires節と、テンプレート特殊化の組み合わせには注意が必要。
例えば制約付きプライマリテンプレート(#1)に対してdouble
型で明示的特殊化(#2)しようとしても、下記記述コードでは#2定義でill-formedになる。これは#1のrequires節によりT=double
のときプライマリテンプレート不在とみなされるため。
#include <concepts> // #1 プライマリテンプレート(?) template<typename T> requires (!std::floating_point<T>) int f(T) { return 0; } // #2 double型による特殊化 template<> int f(double) { return 1; } // NG assert( f(42) == 0 ); assert( f(3.14) == 1 );
テンプレートの明示的特殊化ではなく通常関数によるオーバーロードを行うか、プライマリテンプレートの関連制約(requires節)を削除すれば期待通り動作する。
// #1 制約付きテンプレート template<typename T> requires (!std::floating_point<T>) int f(T) { return 0; } // #2 double型でオーバーロード int f(double) { return 1; } // OK
// #1 プライマリテンプレート template<typename T> int f(T) { return 0; } // #2 double型による特殊化 template<> int f(double) { return 1; } // OK
C++20 13.9.3/p12より引用。
[Note: An explicit specialization of a constrained template is required to satisfy that template's associated constraints (13.5.2). The satisfaction of constraints is determined when forming the template name of an explicit specialization in which all template arguments are specified (13.3), or, for explicit specializations of function templates, during template argument deduction (13.10.2.6) when one or more trailing template arguments are left unspecified. -- end note]
関連URL