【一人 C++20 Advent Calendar 2019】コンパイル時に評価されたかどうかを判別出来る関数を追加【11日目】

一人 C++20 Advent Calendar 2019 11日目の記事になります。

コンパイル時に評価されたかどうかを判別出来る関数を追加

コンパイル時に評価されたかどうかを判別出来る std::is_constant_evaluated() 関数が追加されました。
この関数はコンパイル時に評価された場合は true を返し、実行時に評価された場合は false を返します。
次のようにコンパイル時に評価されたかどうかで処理を切り分けたい場合などに利用できます。

#include <iostream>
#include <type_traits>
#include <cmath>

constexpr double
power(double b, int x) {
    if (std::is_constant_evaluated() && x >= 0) {
        // コンパイル時に評価される場合はこちらの実装を使用する
        double r = 1.0, p = b;
        unsigned u = (unsigned)x;
        while (u != 0) {
          if (u & 1) r *= p;
          u /= 2;
          p *= p;
        }
        return r;
    }
    else {
        return std::pow(b, (double)x);
    }
}

constexpr int
fact(int n){
    if (!std::is_constant_evaluated()) {
        // コンパイル時に評価されない場合はログ出力する
        std::cout << n << std::endl;
    }
    return n > 1 ? n * fact(n - 1) : n;
}


int
main(){
    // constexpr の実装が呼ばれる
    constexpr auto result1 = power(2, 10);
    static_assert(result1 == 1024);

    // std::pow の実装が呼ばれる
    auto result2 = power(2, 10);
    std::cout << result2 << std::endl;

    // 内部で標準出力はされない
    constexpr auto result = fact(6);
    static_assert(result == 720);

    // 内部で標準出力がされる
    fact(6);

    return 0;
}
/*
1024
6
5
4
3
2
1
*/

呼び出され方によって constexpr な関数を呼ぶかどうかみたいなことをするケースだと便利そうですね。
あと『コンパイル時ではなくて実行時の場合のみログ出力したい』みたいな事をしたい場合にも便利そう。 昔はこれってどうやって切り分けてたんだったかなあ…。

追加されたヘッダー

  • <type_traits>

参照