yohhoyの日記

技術的メモをしていきたい日記

requires制約とテンプレート特殊化の関係

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