web-dev-qa-db-ja.com

constexpr関数に切り替えます

Wiki で次のステートメントが見つかりました:

C++ 11では、constexprで宣言された関数の概念が導入されました。コンパイル時に実行できる関数。それらの戻り値は、整数テンプレート引数などの定数式を必要とする操作によって消費される可能性があります。ただし、C++ 11 constexpr関数には、返される単一の式(static_assertsおよびその他の少数の宣言)しか含めることができませんでした。

C++ 14は、これらの制限を緩和します。 Constexprで宣言された関数に次のものが含まれるようになりました。条件付き

  • .。
  • 分岐ステートメントifおよびswitch

それで、c ++ 14/c ++ 17のconstexpr関数にスイッチを入れることは実際に可能ですか?そして、可能であれば、そのための構文は何ですか?たとえば、次のようなものが必要です。

enum class Terrain : std::uintmax_t {
    ROAD,
    SOIL,
    GRASS,
    MUD,
    SNOW,
};

constexpr float
getStepPrice(Terrain const& terrain)
{
    switch constexpr (terrain)
    {
        case Terrain::ROAD: return 1.0f;
        ...
    }
}
7
user6071088

それで、c ++ 14/c ++ 17のconstexpr関数にスイッチを入れることは実際に可能ですか?

はい。

そして、可能であれば、そのための構文は何ですか?

構文について特別なことはまったくありません。通常のswitchです。このような:

constexpr int fun (int i) {
    switch(i) {
        case 0: return 7;
        default: return 5;
    }
}

int main () {
    int arr[fun(3)];
}
14
Baum mit Augen

ではない正確に。 if constexprの場合、結果のコードに分岐がないので安心できます。さらに、破棄されたステートメントはコンパイルする必要はありません。これらは、真のswitch constexprに期待できる保証です。

class Dog;
class Snake;

#define USE_IF

template<typename Pet>
constexpr void foo(Pet pet) {
#ifdef USE_IF
    // This works
    if constexpr(std::is_same_v<Pet, Dog>)   pet.bark();
    else                                     pet.slither();
#else
    // This doesn't
    switch (std::is_same_v<Pet, Dog>) {
        case true:  pet.bark();    break;  // <== Error if Snake
        case false: pet.slither(); break;  // <== Error if Dog
    }
#else
}

ところで、私は、実用的な目的のために、バウムの受け入れられた答えに対して少し気まぐれです。優れたコンパイラーは、constexpr関数、さらにはconstexpr以外のインライン関数を使用して、switch-caseステートメントから論理的に不可能なビットを排除できると思います。

5
JesseC