yohhoyの日記

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

requires式から利用可能な宣言

C++2a(C++20) コンセプト requires式(requires-expression) では、同式を包含するコンテキストのあらゆる宣言を利用できる。

下記コードのrequires式からは関数テンプレートの仮引数xを参照している。requires式の本体(requirement-body)は評価されず(unevaluated)、型情報(型T)のみを利用している。

#include <iostream>
#include <string>
using namespace std::string_literals;

template <typename T>
T doubling(T x)
{
  if constexpr (requires { x.doubling(); }) {
    x.doubling();  // #1
    return x;
  }
  else if constexpr (requires { x * 2; }) {
    return x * 2;  // #2
  }
  else {
    return x + x;  // #3
  }
}

// doublingメンバ関数を持つクラス型
struct X {
  unsigned m_;
  void doubling()
    { m_ <<= 1; }
  friend std::ostream& operator<<(std::ostream& os, const X& x)
    { return os << "X{" << x.m_ << "}"; }
};

std::cout << doubling(3.14);    // 6.28   (#2)
std::cout << doubling("abc"s);  // abcabc (#3)
std::cout << doubling(X{21});   // X{42}  (#1)

1番目constexpr if文の条件式記述では下記の選択肢が考えられる:

  • requires { x.doubling(); }:関数パラメータ宣言を利用
  • requires (T t) { t.doubling(); }:ローカルパラメータ導入と利用
  • requires { T{}.doubling(); }:テンプレートパラメータを利用

N4861 7.5.7/p1-2, 4-5より一部引用(下線部は強調)。

1 A requires-expression provides a concise way to express requirements on template arguments that can be checked by name lookup (6.5) or by checking properties of types and expressions.
 requires-expression:
   requires requirement-parameter-listopt requirement-body
 requirement-parameter-list:
   ( parameter-declaration-clauseopt )
 requirement-body:
   { requirement-seq }
 (snip)
2 A requires-expression is a prvalue of type bool whose value is described below. Expressions appearing within a requirement-body are unevaluated operands (7.2).

4 A requires-expression may introduce local parameters using a parameter-declaration-clause (9.3.3.5). (snip)
5 The requirement-body contains a sequence of requirements. These requirements may refer to local parameters, template parameters, and any other declarations visible from the enclosing context.

関連URL: