C++1z if constexpr文

C++1zから、コンパイル時条件によって分岐するif constexpr文が導入されます。これにより、再帰やヘルパ関数を書かなくて済むケースが多くなります。

D言語にあるstatic if文のようなものです。

template <class T, class... Rest>
void g(T&& p, Rest&&... rs)
{
    if constexpr (sizeof...(rs) > 0) {
        g(rs...); // rs...が空のときのオーバーロードが不要
    }
}

elseの方にはconstexprは必要ありません。 テンプレート内で条件分岐した場合は、到達しなかったブロックはインスタンス化されません。

ただし、条件式内でのコンパイル時条件については全てインスタンス化され、短絡評価によって後ろの方の条件がインスタンス化されないことを期待するようなコードは書けないので注意してください。

if constexpr (has_value_type_v<T> && typename T::value_type())

このような条件式は、else節に進む場合にコンパイルエラーになります。このような条件を書きたい場合は、条件分岐を入れ子にする必要があります。

if constexpr (has_value_type_v<T>) {
    if constexpr (typename T::value_type()) {
        …
    }
}

なお、constexpr ifでなくif constexprになっているのは、前者を採用すると構文として、else ifを書くときにconstexprが二重に必要になってしまうのを避けるためです。

// 採用された構文
if constexpr (cond) {
}
else if constexpr (cond) {
}
else {
}
// 却下された構文
constexpr if (cond) {
}
constexpr else constexpr if (cond) {
}
constexpr else {
}

最初に考えられていたstatic if宣言と違って、if constexpr文はスコープを導入します。また、型や関数を定義する条件分岐には使用できません。

// こういうことはできない。
// 条件によって関数や型の宣言・定義を変えるようなことはできないし、
// クラススコープでif constexpr文は使用できない
struct X {
    if constexpr (cond) {
        void f();
        using int32 = int;
    }
    else {
        void g();
    }
};

参照

お断り

この記事の内容は、C++1zが正式リリースされる際には変更される可能性があります。正式リリース後には、C++日本語リファレンスサイトcpprefjpの以下の階層の下に解説ページを用意する予定です。