C++ 1zでは、「constexpr if」が導入されます。これは、条件に基づいてブランチの1つが削除されるifです。合理的で便利なようです。
しかし、constexprキーワードなしで行うことはできませんか?コンパイル時に、コンパイラはコンパイル時に状態がわかっているかどうかを知る必要があると思います。もしそうなら、最も基本的な最適化レベルでさえ、不要なブランチを削除するはずです。
例(godboltを参照: https://godbolt.org/g/IpY5y5 ):
int test() {
const bool condition = true;
if (condition) {
return 0;
} else {
// optimized out even without "constexpr if"
return 1;
}
}
Godbolt Explorerは、-O0を指定したgcc-4.4.7でも「return1」をコンパイルしなかったため、constexprで約束されたものを達成したことを示しています。明らかに、このような古いコンパイラは、条件がconstexpr関数の結果である場合はそうすることができませんが、事実は残ります。現代のコンパイラは、条件がconstexprであるかどうかを認識しており、明示的に指定する必要はありません。
したがって、問題は次のとおりです。
「constexprif」に「constexpr」が必要なのはなぜですか?
これは例を通して簡単に説明できます。検討する
struct Cat { void meow() { } };
struct Dog { void bark() { } };
そして
template <typename T>
void pet(T x)
{
if(std::is_same<T, Cat>{}){ x.meow(); }
else if(std::is_same<T, Dog>{}){ x.bark(); }
}
呼び出し
pet(Cat{});
pet(Dog{});
コンパイルエラーが発生します (wandbox example) 両方のブランチがif
ステートメントのは整形式である必要があります。
prog.cc:10:40: error: no member named 'bark' in 'Cat'
else if(std::is_same<T, Dog>{}){ x.bark(); }
~ ^
prog.cc:15:5: note: in instantiation of function template specialization 'pet<Cat>' requested here
pet(Cat{});
^
prog.cc:9:35: error: no member named 'meow' in 'Dog'
if(std::is_same<T, Cat>{}){ x.meow(); }
~ ^
prog.cc:16:5: note: in instantiation of function template specialization 'pet<Dog>' requested here
pet(Dog{});
^
pet
をif constexpr
を使用するように変更する
template <typename T>
void pet(T x)
{
if constexpr(std::is_same<T, Cat>{}){ x.meow(); }
else if constexpr(std::is_same<T, Dog>{}){ x.bark(); }
}
ブランチが解析可能である必要があるだけです-条件に一致するブランチだけが整形式である必要があります (wandbox example) 。
スニペット
pet(Cat{});
pet(Dog{});
期待どおりにコンパイルおよび動作します。