constexpr関数の制限緩和


概要

C++11までのconstexpr関数、及びconstexprコンストラクタの関数本体の記述には厳しい制限があった。このため、constexprの関数で複雑な処理を記述する事が難しかった。また、constexpr指定のメンバ関数は暗黙的にconst指定されたものとして扱われるため、同じシグネチャを持つ関数でconst版と非const版のconstexpr関数を混在させる事が出来なかった。 C++では、戻り値の型のみが異なる関数のオーバーロードは許可されていない。

C++14では、これらの制限、制約が緩和されたためconstexpr関数の使用が大きく改善されている。 ここでは、constexpr関数、及びconstexprコンストラクタの本体に記述できる内容について示す。

constexpr関数

C++14のconstexpr関数本体には、以下で示す構文以外が記述可能である。

  • asm定義 (インラインアセンブラ)
  • goto文
  • tryブロック
  • 非リテラル型、もしくはstatic or thread_local指定の変数の定義
  • 初期化が実行されない変数の定義

上記の条件に当てはまらない限り、どのような処理内容であっても記述可能である。

constexpr関数に求められる条件は、C++11のconstexprを参照。 以下にサンプルを示す。

constexpr int square(int x) {       // OK
    return x * x;
}

constexpr long long_max(int x) {    // OK
    return 2147483647;
}

constexpr int abs(int x) {          // OK
    if (x < 0) {
        x = -x;
    }

    return x;
}

constexpr int first(int n) {
    static int value = n;           // error variable has static storage duration.
    return value;
}

constexpr int uninit() {
    int value;                      // error variable is not initialized.
    return value;
}

constexpr int g(int x, int n) {     // OK
    int r=1;
    while (--n > 0) {
        r *= x;
    }
    return r;
}
constexprコンストラクタ

constexprコンストラクタの関数本体に記述可能な構文は、constexpr関数と同じである。 constexprコンストラクタの本体は、= deleteされているか、constexpr関数本体の制約を満たして定義し、かつ、function-try-block を用いていないことが条件である。

constexprコンストラクタに求められる条件は、C++11のconstexprを参照。

class X {
public:
    constexpr X(int x) : x_(x) { }
private:
    int x_;
};

class Y {
public:
    constexpr Y() {}
private:
    int y_ = 1;
};

class Z {
public:
    constexpr Z() try : z_(0) {      //error function-try-block cannot use in constexpr constructor.
    } catch (...) {
    }
}

int main() {
    constexpr X x(1);
    constexpr Y y;
}

results matching ""

    No results matching ""