8.3 constexpr if文

constexprなif文を記述する事ができます。例えば、以下のような場合にこの構文は有効です。

#include<iostream>

constexpr int plus(const int x,const int y){return x+y;}

int main()
{
    constexpr int a=10,b=20;

    if(plus(a,b)==30){
    std::cout<<"thirty!"<<std::endl;
    }else{
    std::cout<<"not thirty!"<<std::endl;
    }
}

実行結果は以下となります。

thirty!

constexpr関数の戻り値によって、処理内容を分岐していますが、通常のif文だと動的な動作という意味になってしまいます。つまり、constexprな変数と、constexprな関数を使ってせっかくコンパイル時に値が定まっていたとしても、if文では30 == 30という演算を実行時に処理してしまうのです。(最適化によっては動的に処理しないコードを生成する可能性もあるが、処理系やコンパイルオプションに依存するため、最適化が必ず発生する事は保証できない。C++の規格ではあくまでも動的に実行される一文として解釈される事が制定されている。)

このような場合には、条件式がコンパイル時に定まる事を規定とした、constexpr if文を使います。

#include<iostream>

constexpr int plus(const int x,const int y){return x+y;}

int main()
{
    constexpr int a=10,b=20;

    if constexpr(plus(a,b)==30){
    std::cout<<"thirty!"<<std::endl;
    }else{
    std::cout<<"not thirty!"<<std::endl;
    }
}

if constexprというようにする事で、その分岐処理は、必ずコンパイル時に行われるようになります。よって、例えば動的な条件式をconstexpr if文で使う事はできません。

#include<iostream>

int plus(int x,int y){return x+y;}

int main()
{
    int a=10,b=20;
    if constexpr(plus(a,b)==30){ // plus関数は静的な関数でないためエラー
        std::cout<<"thirty!"<<std::endl;
    }else{
        std::cout<<"not thirty!"<<std::endl;
    }
}

if constexprの後のelseでは、constexprキーワードを付与する必要はありません。しかし、else if節では、以下のようにelse constexpr ifとする必要があります。

#include<iostream>

constexpr int plus(const int x,const int y){return x+y;}

int main()
{
    constexpr int a=10,b=30;

    if constexpr(plus(a,b)==30){
        std::cout<<"thirty!"<<std::endl;
    }else if constexpr(plus(a,b)==40){
    std::cout<<"fourty!"<<std::endl;
    }else{
        std::cout<<"other"<<std::endl;
    }
}

実行結果は以下となります。

fourty!

因みに以下のように、else if節でconstexprを省くと、それ以降の処理は動的処理となります。

#include<iostream>

int main()
{
    constexpr bool a=false;
    int b=20;

    if constexpr(a){
    std::cout<<"selected a"<<std::endl;
    }else if(b==20){
        std::cout<<"selected b"<<std::endl;
    }else{
        std::cout<<"selected other"<<std::endl;
    }
}

実行結果は以下となります。

selected b

bは動的な変数ですが、else if節でconstexprキーワードが付与されていないため、動的に評価されます。動的なelse ifの後に再度else constexpr ifを記述した場合、再度それ以降の処理はコンパイル時となります。

#include<iostream>

int main()
{
    constexpr bool a=false;
    constexpr int b=30; // # 1

    if constexpr(a){
        std::cout<<"selected a"<<std::endl;
    }else if(b==20){
        std::cout<<"selected b"<<std::endl;
    }else if constexpr(b==30){
        std::cout<<"selected other"<<std::endl;
    }
}

実行結果は以下となります。

selected other

上記のコードの#1部分をconstexprでなくすとどうなるでしょうか。それは、エラーとなります。あくまで、一連のconstexpr if文の中でbをコンパイル時に評価しなければならない条件式が含まれていた場合は、その一部が動的に変数を評価する条件式だとしても、コンパイル時定数である必要があります。

さて、ここまでconstexpr if文について述べてきましたが、今の所あまり有り難みがないかもしれません。この機能のありがたみは、「第11章 テンププレート」の中で知ることとなりますから、覚えておいてください。