名前空間
変種
操作

constexpr 指定子 (C++11以上)

提供: cppreference.com
< cpp‎ | language
 
 
C++言語
一般的なトピック
フロー制御
条件付き実行文
繰り返し文 (ループ)
ジャンプ文
関数
関数宣言
ラムダ関数宣言
inline 指定子
例外指定 (C++20未満)
noexcept 指定子 (C++11)
例外
名前空間
指定子
decltype (C++11)
auto (C++11)
alignas (C++11)
const/volatile
constexpr (C++11)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点
文字 - 文字列 - nullptr (C++11)
ユーザ定義 (C++11)
ユーティリティ
属性 (C++11)
typedef 宣言
型エイリアス宣言 (C++11)
キャスト
暗黙の変換 - 明示的な変換
static_cast - dynamic_cast
const_cast - reinterpret_cast
メモリ確保
クラス
クラス固有の関数特性
特別なメンバ関数
テンプレート
その他
 
 
  • constexpr ー 変数または関数の値が定数式内に現れることができることを指定します。

目次

[編集] 説明

constexpr 指定子は関数または変数の値をコンパイル時に評価できることを宣言します。 そのような変数および関数はコンパイル時定数式のみが使用できる場所で使用できます (適切な引数が与えられれば)。 オブジェクトの宣言または非静的メンバ関数 (C++14未満)で使用された constexpr 指定子は const を暗に含みます。 関数または静的メンバ変数 (C++17以上)の宣言で使用された constexprinline を暗に含みます。 ある関数または関数テンプレートのいずれかの宣言が constexpr 指定子を持つ場合は、すべての宣言がその指定子を含まなければなりません。

constexpr 変数は以下の要件を満たさなければなりません。

  • その型は LiteralType でなければなりません。
  • 直ちに初期化されなければなりません。
  • その初期化の完全式 (すべての暗黙の変換やコンストラクタ呼び出しなどを含みます) は定数式でなければなりません。

constexpr 関数は以下の要件を満たさなければなりません。

  • virtual であってはなりません。
(C++20未満)
  • その戻り値の型は LiteralType でなければなりません。
  • そのすべての引数は LiteralType でなければなりません。
  • 関数の呼び出しがコア定数式の評価された部分式 (コンストラクタの場合は、定数初期化子での使用で十分です) (C++14以上)となるような実引数の集合が少なくともひとつは存在する。 この要件の違反に対して診断は要求されません。
  • 関数の本体は、削除されているか、デフォルト化されているか、以下のみを含まなければなりません。
(C++14未満)
  • 関数の本体は、以下の内容を含んではなりません
  • goto 文。
  • casedefault 以外のラベルの付いた文 。
(C++20未満)
(=default; または =delete; である関数の本体は上記をいずれも含みません。)
(C++14以上)

constexpr コンストラクタは以下の要件を満たさなければなりません。

  • そのすべての引数は LiteralType でなければなりません。
  • クラスは仮想基底クラスを持ってはなりません。
(C++20未満)
  • コンストラクタの本体は、削除されているか、デフォルト化されているか、以下のみを含まなければなりません。
(C++14未満)
  • コンストラクタの本体は constexpr 関数の本体の制約を満たさなければなりません。
(C++14以上)
  • クラスまたは構造体のコンストラクタの場合は、すべての基底クラス部分オブジェクトおよびすべての変種でない非静的データメンバは初期化されなければなりません。 クラスが union ライクなクラスの場合は、空でない無名の union メンバのそれぞれについて、ちょうど1個の変種メンバが初期化されなければなりません。
  • 空でない union のコンストラクタの場合は、ちょうど1個の非静的データメンバが初期化されなければなりません。
  • 非静的メンバおよび基底クラスを初期化するために選択されたすべてのコンストラクタは constexpr でなければなりません。

constexpr 関数テンプレートおよびクラステンプレートの constexpr メンバ関数の場合は、少なくとも1個の特殊化は上記の要件を満たさなければなりません。 他の特殊化は、たとえそのような関数の呼び出しが定数式に現れることができなくとも、 constexpr とみなされます。

[編集] ノート

noexcept 演算子は定数式に対しては必ず true を返すため、 constexpr 関数の特定の呼び出しが定数式の分岐を取ったかどうかをチェックするために使用できます。

constexpr int f(); 
constexpr bool b1 = noexcept(f()); // false、未定義の constexpr 関数。
constexpr int f() { return 0; }
constexpr bool b2 = noexcept(f()); // true、 f() は定数式です。
(C++17未満)

constexpr コンストラクタはリテラル型でないクラスに対しても使用できます。 例えば std::unique_ptr のデフォルトコンストラクタは constexpr であり、これによって定数初期化が可能となります。

参照変数は constexpr 宣言できます (初期化子は参照定数式である必要があります)。

static constexpr int const& x = 42; // const int オブジェクトへの constexpr 参照
                                    // (static な参照による生存期間延長のため
                                    //  このオブジェクトは静的記憶域期間を持ちます)。

constexpr 関数内で try ブロックおよびインラインアセンブリは許されていますが、定数式内で例外を投げることやアセンブリを実行することは未だ許されていません。

(C++20以上)

[編集] キーワード

constexpr

[編集]

階乗を計算する C++11 の constexpr 関数と文字列リテラルを拡張するリテラル型の定義。

#include <iostream>
#include <stdexcept>
 
// C++11 の constexpr 関数は繰り返しではなく再帰を使用します
// (C++14 の constexpr 関数はローカル変数やループを使用できます)。
constexpr int factorial(int n)
{
    return n <= 1 ? 1 : (n * factorial(n - 1));
}
 
// リテラルクラス。
class conststr {
    const char* p;
    std::size_t sz;
public:
    template<std::size_t N>
    constexpr conststr(const char(&a)[N]): p(a), sz(N - 1) {}
 
    // constexpr 関数は例外を投げることによってエラーを知らせます。
    // C++11 では条件演算子 ?: でそれを行わなければなりません。 
    constexpr char operator[](std::size_t n) const
    {
        return n < sz ? p[n] : throw std::out_of_range("");
    }
    constexpr std::size_t size() const { return sz; }
};
 
// C++11 の constexpr 関数は単一の return 文にすべてを詰め込む必要がありました
// (C++14 にはその要件はありません)。
constexpr std::size_t countlower(conststr s, std::size_t n = 0,
                                             std::size_t c = 0)
{
    return n == s.size() ? c :
           'a' <= s[n] && s[n] <= 'z' ? countlower(s, n + 1, c + 1) :
                                       countlower(s, n + 1, c);
}
 
// テスト用のコンパイル時定数を要求する出力関数。
template<int n>
struct constN
{
    constN() { std::cout << n << '\n'; }
};
 
int main()
{
    std::cout << "4! = " ;
    constN<factorial(4)> out1; // コンパイル時に計算されます。
 
    volatile int k = 8; // volatile を用いて最適化を妨げます。
    std::cout << k << "! = " << factorial(k) << '\n'; // 実行時に計算されます。
 
    std::cout << "the number of lowercase letters in \"Hello, world!\" is ";
    constN<countlower("Hello, world!")> out2; // conststr に暗黙に変換されます。
}

出力:

4! = 24
8! = 40320
the number of lowercase letters in "Hello, world!" is 9

[編集] 欠陥報告

以下の動作変更欠陥報告は以前に発行された C++ 標準に遡って適用されました。

DR 適用先 発行時の動作 正しい動作
CWG 1911 C++14 constexpr constructors for non-literal types were not allowed allowed in constant initialization
CWG 2004 C++14 copy/move of a union with a mutable member was allowed in a constant expression mutable variants disqualify implicit copy/move
CWG 2163 C++14 labels were allowed in constexpr functions even though gotos are prohibited labels also prohibited
CWG 2268 C++14 copy/move of a union with a mutable member was prohibited by cwg 2004 allowed if the object was created within the constant expression

[編集] 関連項目