constexpr
の拡張バージョン(C++ 14からだと思います)なので、「実際の」constexpr
として使用できるconstexpr
関数を宣言できます。つまり、コードコンパイル時に実行されるか、インライン関数として動作します。だから、このプログラムを持つことができるとき:
_#include <iostream>
constexpr int foo(const int s) {
return s + 4;
}
int main()
{
std::cout << foo(3) << std::endl;
const int bar = 3;
std::cout << foo(bar) << std::endl;
constexpr int a = 3;
std::cout << foo(a) << std::endl;
return 0;
}
_
結果は次のとおりです。
_7
7
7
_
ここまでは順調ですね。
関数がコンパイル時または実行時に実行されるかどうかをfoo(const int s)
で知る方法(おそらく標準)はありますか?
編集:関数がコンパイル時に評価されたかどうかを実行時に知ることも可能ですか?
記載されている手法は機能しますが、static_assert
sfinaeフレンドリーではありません。これを行うためのより良い方法(理論的には、私の意味がわかります)は、関数がnoexcept
であるかどうかを確認することです。どうして?なぜなら、関数がそのようにマークされていなくても、定数式は常に例外ではないからです。したがって、次のコードを検討してください。
template <class T>
constexpr void test_helper(T&& t) {}
#define IS_CONSTEXPR(...) noexcept(test_helper(__VA_ARGS__))
test_helper
はconstexpr
であるため、引数がある限り、定数式になります。定数式の場合はnoexcept
になりますが、それ以外の場合はそうなりません(そのようにマークされていないため)。
それでは、これを定義しましょう:
double bar(double x) { return x; }
constexpr double foo(double x, bool b) {
if (b) return x;
else return bar(x);
}
foo
が定数式であり、noexcept
がtrueの場合、x
はb
のみです。ブール値がfalseの場合、constexpr
以外の関数を呼び出し、constexpr-nessを台無しにします。それで、これをテストしましょう:
double d = 0.0;
constexpr auto x = IS_CONSTEXPR(foo(3.0, true));
constexpr auto y = IS_CONSTEXPR(foo(3.0, false));
constexpr auto z = IS_CONSTEXPR(foo(d, true));
std::cerr << x << y << z;
コンパイルできました。これにより、コンパイル時のブール値(コンパイルエラーではなく)が得られます。たとえば、sfinaeに使用できます。
キャッチ?まあ、clangには複数年のバグがあり、これを正しく処理していません。ただし、gccにはあります。ライブの例: http://coliru.stacked-crooked.com/a/e7b037932c358149 。本来の「100」を出力します。
C++ 20では、ヘッダーis_constant_evaluated
で定義されている<type_traits>
が導入され、この問題に対処しています。
constexpr int foo(int s)
{
if (std::is_constant_evaluated()) // note: not "if constexpr"
/* evaluated at compile time */;
else
/* evaluated at run time */;
}
ここでは、if constexpr
の代わりに通常のif
が使用されていることに注意してください。 if constexpr
を使用する場合は、コンパイル時に条件を評価する必要があるため、is_constant_evaluated
は常にtrueを返し、テストが役に立たなくなります。
それを行うための正規の方法はstatic_assert
。 static_assert
sはコンパイル時に評価されるため、条件がfalseの場合はビルドが中断されます。
#include <iostream>
constexpr int foo(const int s) {
return s + 4;
}
int main()
{
std::cout << foo(3) << std::endl;
const int bar = 3;
std::cout << foo(bar) << std::endl;
constexpr int a = 3;
std::cout << foo(a) << std::endl;
static_assert(foo(3) == 7, "Literal failed");
static_assert(foo(bar) == 7, "const int failed");
static_assert(foo(a) == 7, "constexpr int failed");
return 0;
}
clang++ -std=c++14 so1.cpp
は問題なくコンパイルされ、すべてが期待どおりに機能することを示しています。
constexpr
関数内では、constexpr
コンテキストで評価されているかどうかはわかりません。この機能を追加するための多くの提案があります。 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0595r2.html が成功しました。 c ++ 20 に出現し、 c ++ 21 。
constexpr
関数の外では、特定の引数のセットを持つ関数の呼び出しがconstexpr
コンテキストで評価されるかどうかを判断する方法がいくつかあります。最も簡単なのは、constexpr
を必要とするコンテキストで結果を使用することです。
Constexpr式が非void整数型またはポインター型(関数ポインターを含む)を返すと仮定します。
_#define CONSTEXPR_EVAL(...) \
std::integral_constant< \
std::decay_t<decltype(__VA_ARGS__)>, \
__VA_ARGS__ \
>::value
_
CONSTEXPR_EVAL( bar(foo, true) )
は、bar(foo, true)
がコンパイル時に評価できない場合はコンパイルに失敗し、コンパイル時に評価できる場合はその値を返します。
noexcept
(コンパイル時に評価される関数はnoexcept
)を含む他のトリックが機能します( @ NirFriedmanの回答 を参照) 。
パーティーを台無しにして申し訳ありませんが、確かに標準のやり方はありません。 as-ifルールでは、コンパイル時に別のコンテキストで強制的に計算するように強制されている場合でも、コンパイラーは実行時に結果を計算するコードを発行できます。コンパイル時に実行できることは、実行時に再度実行できますか?そして、計算はスローしないことがすでに証明されています。
拡張により、標準に準拠したIS_REALLY_CONSTEXPR
またはis_really_constexpr
checkは、まったく同じ呼び出し、またはさらに言えば、まったく同じconstexpr
シンボルの値が実行時間の計算に関係することを証明できません。
もちろん、通常は実行時に計算を繰り返す理由はありませんが、コンパイル時にすでに実行されている場合もありませんが、問題は、コンパイラが事前計算された結果を使用するかどうかを伝えることでした。 。
おそらく標準と言ったので、実際には、提供されたソリューションの1つを選択したコンパイラでテストし、それが一貫して動作することを期待するのがおそらく最善の策です。 (または、オープン/パブリックソースであり、その傾向がある場合は、ソースコードを読み取ります。)