yohhoyの日記

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

C++ Conceptsの短縮構文(P1141R2)

次期C++2a(C++20)標準仕様に向けて採択された、コンセプト(concept)関連の短縮構文についてメモ。C++コンセプト概略ついては id:yohhoy:20170904 を参照のこと。

本記事の内容はP1141R2 Yet another approach for constrained declarationsに基づく。

要約:

  • autoキーワードによる関数テンプレート定義が可能。“template-less Function Template”
  • 現行autoキーワードを用いた型推論にて、コンセプト名による制約付けが可能。

関数テンプレートパラメータTへのコンセプトC指定では、下記構文のいずれかを用いて制約(constraint)を指定できる。短縮関数テンプレート(abbreviated function template)構文が新たに追加され、templateキーワードを用いない関数テンプレート定義が可能となる。(→id:yohhoy:20150303)

// C++2a
// 型パラメータTに対するコンセプトC
template <typename T> concept C = /*...*/;

// A) 制約付きパラメータ(constrained-parameter)による制約
template <C T>
void func(T arg);

// B) requires節(requires-clause)による制約
template <typename T> requires C<T>
void func(T arg);

// C) 末尾requires節(trailing requires-clause)による制約
template <typename T>
void func(T arg) requires C<T>;

// D) ★短縮関数テンプレート(abbreviated function template)構文
void func(C auto arg);

// D') ★コンセプト制約なし短縮関数テンプレート
void func1(auto arg);

従来からパラメータ型宣言でautoキーワードを利用していたジェネリックラムダ(generic lambda)でも同様の構文となる。

// C++14以降: ジェネリックラムダ
auto lm0 = [](auto arg) { /*...*/ };
// C++2a: ジェネリックラムダのテンプレート構文
auto lm0 = []<typename T>(T arg) { /*...*/ };

// C++2a: テンプレートパラメータ型制約付きジェネリックラムダ(4パターン)
auto lm1 = []<C T>(T arg) { /*...*/ };
auto lm1 = []<typename T> requires C<T> (T arg) { /*...*/ };
auto lm1 = []<typename T> (T arg) requires C<T> { /*...*/ };
auto lm1 = [](C auto arg) { /*...*/ };  // ★P1141R2で導入

autoキーワードを用いた関数の戻り値型推論や変数型推論においても、推論される型に対してコンセプトCによる制約付けが行える。いずれもautoキーワードは必須であり、コンセプト名のみ(C f2();C v2;)ではill-formedとなる。

// 戻り値型に制約なし
auto f0() {
  return /*...*/;
}
decltype(auto) h0() {
  return /*...*/;
}
// 変数型に制約なし
auto v0 = f0();

// C++2a: 戻り値型はコンセプトCを満たすべき
C auto f1() {
  return /*...*/;
}
C decltype(auto) h1() {
  return /*...*/;
}
// C++2a: 変数型はコンセプトCを満たすべき
C auto v1 = f1();

関連URL