こんにちは!
ステートメントをアサートするためにカスタムメッセージを追加する方法を探しています。この質問を見つけました assertにカスタムメッセージを追加しますか? しかし、メッセージはそこで静的です。私はこのようなことをしたい:
assert((0 < x) && (x < 10), std::string("x was ") + myToString(x));
アサーションが失敗すると、通常の出力に加えて、たとえば「x was 100」が必要になります。
あなたはここで不運です。最善の方法は、独自のassert
マクロを定義することです。
基本的には次のようになります。
#ifndef NDEBUG
# define ASSERT(condition, message) \
do { \
if (! (condition)) { \
std::cerr << "Assertion `" #condition "` failed in " << __FILE__ \
<< " line " << __LINE__ << ": " << message << std::endl; \
std::terminate(); \
} \
} while (false)
#else
# define ASSERT(condition, message) do { } while (false)
#endif
これは、デバッグなしマクロASSERT
が定義されていない場合にのみ、NDEBUG
マクロを定義します。
次に、次のように使用します。
ASSERT((0 < x) && (x < 10), "x was " << x);
"x was "
とx
を明示的に文字列化する必要がないため、これは使用よりも少し簡単です。これはマクロによって暗黙的に行われます。
独自のルーチンを作成せずにメッセージを含めるには、いくつかの古いトリックがあります。
最初はこれです:
bool testbool = false;
assert(("this is the time", testbool));
もあります:
bool testbool = false;
assert(testbool && "This is a message");
内側の括弧式の結果は 'testbool'の値であるため、最初のものが機能します。文字列の値はゼロ以外になるため、2番目の方法は機能します。
より良い代替方法は、デバッガーが失敗したときにアサートで停止するように指示することです。その後、x値だけでなく、呼び出しスタックを含むその他の情報を調べることができます。おそらく、これはあなたが本当に探しているものです。ここにサンプル実装が記載されています C++でプログラミングする場合、一部のメソッドがクラスにまだ実装されていないことを共同プログラマに示す方法
#define ASSERT_WITH_MESSAGE(condition, message) do { \
if (!(condition)) { printf((message)); } \
assert ((condition)); } while(false)
完全を期すために、C++でマクロ実装をアサートするドロップイン2ファイルを公開しました。
_#include <pempek_assert.h>
int main()
{
float min = 0.0f;
float max = 1.0f;
float v = 2.0f;
PEMPEK_ASSERT(v > min && v < max,
"invalid value: %f, must be between %f and %f", v, min, max);
return 0;
}
_
次のプロンプトが表示されます。
_Assertion 'v > min && v < max' failed (DEBUG)
in file e.cpp, line 8
function: int main()
with message: invalid value: 2.000000, must be between 0.000000 and 1.000000
Press (I)gnore / Ignore (F)orever / Ignore (A)ll / (D)ebug / A(b)ort:
_
どこ
abort()
(Windowsでは、システムはユーザーにデバッガーを接続するように要求します)abort()
をすぐに呼び出しますあなたはそれについてもっと知ることができます:
お役に立てば幸いです。
はい、これは可能です。
better_assert((0 < x) && (x < 10), std::string("x was ") + myToString(x));
のような式を有効にするには、対応するマクロを次の形式で持つ必要があります。
_#define better_assert(EXPRESSION, ... ) ((EXPRESSION) ? \
(void)0 : print_assertion(std::cerr, \
"Assertion failure: ", #EXPRESSION, " in File: ", __FILE__, \
" in Line: ", __LINE__ __VA_OPT__(,) __VA_ARGS__))
_
ここで、_print_assertion
_はアサーションを実行するプロキシ関数です。 EXPRESSION
が評価されると、false
、すべてのデバッグ情報、___VA_ARGS__
_が_std::cerr
_にダンプされます。この関数は任意の数の引数を受け取るため、可変個引数テンプレート関数を実装する必要があります。
_template< typename... Args >
void print_assertion(std::ostream& out, Args&&... args)
{
out.precision( 20 );
if constexpr( debug_mode )
{
(out << ... << args) << std::endl;
abort();
}
}
_
前の実装では、式_(out << ... << args) << std::endl;
_はC++ 17のfold式を使用します( https://en.cppreference.com/w/cpp/language/fold );定数式_debug_mode
_は、渡されるコンパイルオプションに関連しており、次のように定義できます。
_#ifdef NDEBUG
constexpr std::uint_least64_t debug_mode = 0;
#else
constexpr std::uint_least64_t debug_mode = 1;
#endif
_
また、式if constexpr( debug_mode )
は、C++からインポートされたif( https://en.cppreference.com/w/cpp/language/if )がconstexprを使用することにも言及する価値があります。 17。
すべてをまとめるために、次のものがあります。
_#ifdef NDEBUG
constexpr std::uint_least64_t debug_mode = 0;
#else
constexpr std::uint_least64_t debug_mode = 1;
#endif
template< typename... Args >
void print_assertion(std::ostream& out, Args&&... args)
{
out.precision( 20 );
if constexpr( debug_mode )
{
(out << ... << args) << std::endl;
abort();
}
}
#ifdef better_assert
#undef better_assert
#endif
#define better_assert(EXPRESSION, ... ) ((EXPRESSION) ? (void)0 : print_assertion(std::cerr, "Assertion failure: ", #EXPRESSION, " in File: ", __FILE__, " in Line: ", __LINE__ __VA_OPT__(,) __VA_ARGS__))
_
その使用法を示す典型的なテストケースは次のとおりです。
_double const a = 3.14159265358979;
double const b = 2.0 * std::asin( 1.0 );
better_assert( a==b, " a is supposed to be equal to b, but now a = ", a, " and b = ", b );
_
これにより、次のようなエラーメッセージが生成されます。
_Assertion failure: a==b in File: test.cc in Line: 9 a is supposed to be equal to b, but now a = 3.1415926535897900074 and b = 3.141592653589793116
[1] 8414 abort (core dumped) ./test
_
完全なソースコードは、このリポジトリで入手できます。 https://github.com/fengwang/better_assert
Kondrad Rudolphの答えを拡張する:
#include <iostream>
#ifdef NDEBUG
#define assert(condition, message) 0
#else
#define assert(condition, message)\
(!(condition)) ?\
(std::cerr << "Assertion failed: (" << #condition << "), "\
<< "function " << __FUNCTION__\
<< ", file " << __FILE__\
<< ", line " << __LINE__ << "."\
<< std::endl << message << std::endl, abort(), 0) : 1
#endif
void foo() {
int sum = 0;
assert((sum = 1 + 1) == 3, "got sum of " << sum << ", but expected 3");
}
int main () {
foo();
}
出力は...
Assertion failed: ((sum = 1 + 1) == 3), function foo, file foo.cpp, line 13.
got sum of 2, but expected 3
zsh: abort ./a.out
これは、std :: assertマクロが追加のユーザー定義メッセージを使用してシステムに出力するものに似ています