Open6

const, constexpr, consteval, constinit ...

蒼百合蒼百合

const

int * ptr1; /* pointer to int */ 
int const * ptr2; /* pointer to "int const" */ 
const int * ptr3; /* pointer to "const int" */ 
int * const ptr4; /* constant pointer to "int" */ 
const int * const ptr5; /* constant pointer to "const int" */ 
  • ptr1int へのポインタ
  • ptr2int const へのポインタ
    • ポインタの指す先の値は int const なので不変
  • ptr3const int へのポインタ
    • ポインタの指す先の値は const int なので不変
  • ptr4int への定数ポインタ
    • ポインタの指す先の値は int なので可変
    • ポインタそのものは不変
  • ptr5const int への 定数ポインタ
    • ポインタの指す先の値は const int なので不変
    • ポインタそのものも不変

定数は const <type>, <type> const のどちらで記述しても良いが,定数ポインタは <type>* const ptr のように * の後に const を記述する.

int const, const int は同義なので ptr2, ptr3 は同義

int * const ptr の記法に従うならば const int var より int const var の方が自然なのかもしれない.

蒼百合蒼百合

constexpr

constexpr auto foo(int n) -> bool {
  auto var = 42;

  if (n + var != 42) { var = 42 - n; }

  return n + var;
}

constexpr はコンパイル時計算する関数に付ける.
コンパイル時計算には引数が constexpr でなければならず,そうでない場合は実行時計算される.
また関数内部で関数外部の変数を参照する場合はその変数が constexpr でなければならず,そうでない場合はエラーとなる.

実行時定数には const を,コンパイル時定数には constexpr を付ける

追記 (C++14での制限緩和について)

constexpr な関数では主に以下が許可されている

  • ローカル変数の宣言
  • ローカル変数・非静的メンバ変数の書き換え
  • if, switch による条件分岐
  • for, while, do-while によるループ

C++11 では return 文しか許可されなかったが,C++14から大幅に緩和された

蒼百合蒼百合

知識をアップデートできていませんでした.ありがとうございます.
ご指摘を受けて修正しました.

蒼百合蒼百合

consteval

consteval auto foo(int n) -> int {
  return n * n;
}

auto main() -> int {
  constexpr auto svar_1 = foo(5); /* OK */

  auto dvar = 5;
  constexpr auto svar_2 = foo(dynvar); /* NG */
}

constevalconstexpr 関数と同様にコンパイル時計算する関数に付けるが,こちらはより厳密である.
constexpr 関数と同様にコンパイル時計算には引数が constexpr でなければならないが,そうでない場合はエラーとなる.

蒼百合蒼百合

constinit

/* global */
constinit auto pi = 3.14;
/* local */
auto main() -> int {
  static constinit auto phi = 1.618;
}

constinit はコンパイル時静的初期化する定数に付ける.
静的 なのでローカルで宣言するなら static を付ける必要がある.