Skip to content

Latest commit

 

History

History
258 lines (201 loc) · 13 KB

File metadata and controls

258 lines (201 loc) · 13 KB

constant_wrapper

  • utility[meta header]
  • std[meta namespace]
  • class template[meta id-type]
  • cpp26[meta cpp]
  • cw[meta alias]
namespace std {
  template <auto X, class = decltype(X)>
  struct constant_wrapper;

  // 型Tが定数として扱えることを表す説明用コンセプト
  template <class T>
  concept constexpr-param =
    requires { typename constant_wrapper<T::value>; };

  // すべての演算子オーバーロードを提供する説明用の基底クラス
  struct cw-operators;

  // constant_wrapperを簡潔に生成する変数テンプレート
  template <auto X>
  constexpr auto cw = constant_wrapper<X>{};
}

概要

constant_wrapperクラステンプレートは、定数Xを型として包むことで、その値を「型の世界」で扱えるようにするためのラッパーである。

constant_wrapperのみで構成された式は、それが現れる文脈に関わらず、常にコア定数式として評価される。これによって、通常はテンプレート引数としてしか渡せない定数を、関数の引数として渡しても定数式として利用できるようになる。とくに、テンプレート引数を明示的に指定できないコンストラクタ呼び出しなどで有用である。

変数テンプレートcwを使うと、std::constant_wrapper<42>{}と書く代わりにstd::cw<42>と簡潔に書ける。

// 通常の定数を関数引数として受け取り、コンパイル時に計算する
constexpr auto add(auto a, auto b)
{
  return a + b;
}

auto result = add(std::cw<42>, std::cw<13>); // resultはconstant_wrapper<55>型
static_assert(result == 55);                 // resultが定数式でなくても、その値は定数式

constant_wrapperはあらゆる演算子をオーバーロードしている。オペランドがすべてconstant_wrapperである場合は、演算結果もconstant_wrapperになり、「型の世界」にとどまる。オペランドのいずれかが通常の値である場合は、保持する値にアンラップされて通常の演算がおこなわれる。

クラステンプレートconstant_wrapperの2つめのテンプレートパラメータは無名であり、引数依存の名前探索 (ADL) を補助するために存在する。これによって、包んでいる値が引数として適合するオーバーロードを、constant_wrapper自身が適合しない場合でも発見できるようになる。

メンバ関数

名前 説明 対応バージョン
(constructor) デフォルトコンストラクタ(暗黙定義) C++26
operator= 代入(valueconstのためconstant_wrapperでは不適格) C++26
operator value_type 保持する値への変換演算子 C++26
operator() 保持する値を関数として呼び出す(静的メンバ関数) C++26
operator[] 保持する値に添字アクセスする(静的メンバ関数) C++26

また、説明用の基底クラスcw-operatorsから以下の擬似的な変更操作を継承する。ただしconstant_wrapperが保持するvalueconstであるため、これらの演算子と上記operator=は、保持する値そのものを変更する式(++valuevalue op= xvalue = x)が不適格となり、constant_wrapperに対してはオーバーロード解決に参加しない(使用できない)。

名前 説明 対応バージョン
operator++ インクリメント C++26
operator-- デクリメント C++26
operator+= 加算の複合代入 C++26
operator-= 減算の複合代入 C++26
operator*= 乗算の複合代入 C++26
operator/= 除算の複合代入 C++26
operator%= 剰余の複合代入 C++26
operator&= ビット論理積の複合代入 C++26
operator|= ビット論理和の複合代入 C++26
operator^= ビット排他的論理和の複合代入 C++26
operator<<= 左シフトの複合代入 C++26
operator>>= 右シフトの複合代入 C++26

メンバ型

名前 説明 対応バージョン
type constant_wrapper自身を表す型 C++26
value_type 保持する値の型 decltype(X)、すなわちラップした値Xの型 C++26

たとえばstd::cw<42>Xint42)の場合、typestd::constant_wrapper<42>value_typeintとなる。

静的メンバ変数

名前 説明 設定される値・型 対応バージョン
value 保持する定数値への参照 テンプレート引数Xへの参照(static constexpr decltype(auto) value = (X);)。型はconst value_type& C++26

たとえばstd::cw<42>の場合、valueの値は42、その型はconst int&となる。valueはテンプレートパラメータオブジェクトへの参照であるため、ダングリングしない。

非メンバ(Hidden friends)関数

constant_wrapperは、説明用の基底クラスcw-operatorsを継承することで、以下の演算子を Hidden friends として提供する。

いずれの演算子も、オペランドがすべて説明用コンセプトconstexpr-paramconstant_wrapperのように、静的メンバvalueを定数として持つ型)のモデルであることを要求し、演算結果を包んだconstant_wrapperを返す。

名前 説明 対応バージョン
operator+ 単項+ C++26
operator- 単項-(符号反転) C++26
operator~ ビット反転 C++26
operator! 論理否定 C++26
operator& 単項&(アドレス取得) C++26
operator* 単項*(間接参照) C++26
operator+ 加算 C++26
operator- 減算 C++26
operator* 乗算 C++26
operator/ 除算 C++26
operator% 剰余 C++26
operator<< 左シフト C++26
operator>> 右シフト C++26
operator& ビット論理積 C++26
operator| ビット論理和 C++26
operator^ ビット排他的論理和 C++26
operator&& 論理積 C++26
operator|| 論理和 C++26
operator<=> 三方比較 C++26
operator< 左辺が右辺より小さいかの判定 C++26
operator<= 左辺が右辺以下かの判定 C++26
operator> 左辺が右辺より大きいかの判定 C++26
operator>= 左辺が右辺以上かの判定 C++26
operator== 等値比較 C++26
operator!= 非等値比較 C++26
operator, カンマ演算子(delete定義) C++26
operator->* メンバポインタ参照 C++26
namespace std {
  template <auto X>
  constexpr auto cw = constant_wrapper<X>{};
}

cwは、constant_wrapper<X>のオブジェクトを簡潔に生成するための変数テンプレートである。std::cw<X>std::constant_wrapper<X>{}と等価である。

備考

  • operator()operator[]は静的メンバ関数であり、保持する値valueをアンラップして呼び出す。引数がすべてconstexpr-paramのモデルであり、その結果をふたたびconstant_wrapperで包める場合は、包んだconstant_wrapperを返す。そうでない場合は、アンラップした結果をそのまま返す。
    • この「保持する値そのものになる。ただし包んだままにできるなら包んだままにする」という規則は、すべての演算子に共通する。たとえば、std::cw<1> + 1int2に、std::cw<1> + std::cw<1>constant_wrapper<2>になる。
  • operator,(カンマ演算子)はdelete定義されている。

基本的な使い方

#include <utility>
#include <iostream>

// 定数を通常の関数引数として受け取り、コンパイル時に計算する高階関数
constexpr auto add(auto a, auto b)
{
  return a + b;
}

int main()
{
  // cw<42>とcw<13>は、値を型として保持する
  auto result = add(std::cw<42>, std::cw<13>);

  // resultはconstant_wrapper<55>型であり、
  // result自身が定数式でなくても、その値は定数式として使用できる
  static_assert(result == 55);

  std::cout << result << std::endl;
}
  • std::cw[color ff0000]

出力

55

演算結果を型として保持する

#include <utility>
#include <type_traits>

int main()
{
  // オペランドがすべてconstant_wrapperなら、演算結果も再びconstant_wrapperになる
  auto a = std::cw<10> + std::cw<5>;
  static_assert(std::is_same_v<decltype(a), std::constant_wrapper<15>>);

  // オペランドのいずれかが通常の値なら、保持する値へアンラップして演算する
  auto b = std::cw<10> + 5;
  static_assert(std::is_same_v<decltype(b), int>);
}
  • std::cw[color ff0000]
  • std::constant_wrapper[color ff0000]

出力

関数や添字をアンラップして呼び出す

#include <utility>
#include <iostream>

constexpr int triple(int x) { return x * 3; }

// constant_wrapperはNTTPとして使うために名前空間スコープに置く
constexpr int data[] = {0, 10, 20, 30};

int main()
{
  // cw<triple>を関数呼び出しすると、保持する関数を呼び出す
  // 引数もconstant_wrapperなら、結果を再びconstant_wrapperで包む
  auto r = std::cw<triple>(std::cw<7>);
  static_assert(r == 21);
  std::cout << r << std::endl;

  // 配列を保持して添字アクセスする
  auto e = std::cw<data>[std::cw<2>];
  static_assert(e == 20);
  std::cout << e << std::endl;
}
  • std::cw[color ff0000]

出力

21
20

バージョン

言語

  • C++26

処理系

  • Clang: 23 [mark verified]
  • GCC: 16.1 [mark verified]
  • Visual C++: 2026 Update 2 [mark noimpl]

関連項目

参照