以前、引数が であるかどうかに基づく関数のオーバーロードconstexpr
について質問しました。その質問に対する残念な答えを回避して、よりスマートなアサート関数を作成しようとしています。これは大まかに私がやろうとしていることです:
inline void smart_assert (bool condition) {
if (is_constexpr (condition))
static_assert (condition, "Error!!!");
else
assert (condition);
}
基本的に、コンパイル時にチェックできるのであれば、コンパイル時チェックは常に実行時チェックよりも優れているという考えです。ただし、インライン化や定数の折りたたみなどにより、コンパイル時のチェックが可能かどうかを常に知ることはできません。assert (condition)
これは、コンパイルしてassert(false)
コードが実行されるのを待っているだけで、エラーがあることに気付く前にそのパスを実行する場合があることを意味します。
したがって、(インライン化またはその他の最適化により) 条件が constexpr であるかどうかを確認する方法があれば、static_assert
可能な場合は呼び出し、それ以外の場合は実行時のアサートにフォールバックできます。幸いなことに、gcc には組み込みのがあり、 が constexpr__builtin_constant_p (exp)
の場合に true を返します。exp
他のコンパイラにこの組み込み関数があるかどうかはわかりませんが、これで問題が解決することを期待していました。これは私が思いついたコードです:
#include <cassert>
#undef IS_CONSTEXPR
#if defined __GNUC__
#define IS_CONSTEXPR(exp) __builtin_constant_p (exp)
#else
#define IS_CONSTEXPR(exp) false
#endif
// TODO: Add other compilers
inline void smart_assert (bool const condition) {
static_assert (!IS_CONSTEXPR(condition) or condition, "Error!!!");
if (!IS_CONSTEXPR(condition))
assert (condition);
}
#undef IS_CONSTEXPR
は、のstatic_assert
短絡動作に依存していor
ます。IS_CONSTEXPR
が真の場合、使用static_assert
でき、条件は!true or condition
であり、これは単に と同じcondition
です。IS_CONSTEXPR
が false の場合はstatic_assert
使用できず、条件は!false or condition
であり、これは と同じでtrue
あり、static_assert
は無視されます。static_assert
が constexpr ではないためにチェックできない場合は、最後の努力としてcondition
ランタイムをコードに追加します。assert
ただし、引数が であっても、関数の引数を astatic_assert
で使用できないため、これは機能しません。constexpr
特に、gcc でコンパイルしようとすると、次のようになります。
// main.cpp
int main () {
smart_assert (false);
return 0;
}
g++ main.cpp -std=c++0x -O0
すべて問題なく、正常にコンパイルされます。最適化なしのインライン化はないため、IS_CONSTEXPR
false であり、static_assert
無視されるため、実行時assert
ステートメント (失敗) を取得するだけです。でも、
[david@david-desktop test]$ g++ main.cpp -std=c++0x -O1
In file included from main.cpp:1:0:
smart_assert.hpp: In function ‘void smart_assert(bool)’:
smart_assert.hpp:12:3: error: non-constant condition for static assertion
smart_assert.hpp:12:3: error: ‘condition’ is not a constant expression
最適化をオンにしてstatic_assert
トリガーを許可するとすぐに、 で関数引数を使用できないため、失敗しますstatic_assert
。これを回避する方法はありますか (それが私自身の実装を意味する場合でもstatic_assert
)? 私の C++ プロジェクトは、できるだけ早くエラーをキャッチするよりスマートな assert ステートメントから理論的にかなりの恩恵を受けることができると思います。
smart_assert
関数のようなマクロを作成しても、一般的なケースでは問題が解決しないようです。この単純な例では明らかにcondition
機能しますが、コール グラフの 2 レベル上の関数から発生した可能性があります (ただし、constexpr
インライン化により、コンパイラには認識されるようになります)。これは、関数パラメーターを使用する場合と同じ問題に遭遇します。でstatic_assert
。