Ответ 1
Вы можете определить свой собственный макрос
#define ASSERT_WITH_MSG(cond, msg) do \
{ if (!(cond)) { std::ostringstream str; str << msg; std::cerr << str.str(); std::abort(); } \
} while(0)
В моей программе я хочу использовать утверждения, отображающие сообщение об ошибке. Помимо известных обходных решений для C и С++ там "реальное" решение как BOOST предлагает BOOST_ASSERT_MSG( expr, msg )
(см. Также assert() с сообщением)
Но статического сообщения для меня недостаточно, я также хочу иногда показывать неудавшиеся переменные, например. в случае типа
BOOST_ASSERT_MSG( length >= 0, "No positive length found! It is " << length )
Как вы можете видеть, я хотел бы отформатировать сообщение "строка" как stringstream
или ostream
, так как это позволило бы мне легко показать пользовательские типы (при условии, что я определил соответствующую функцию форматирования).
Проблема в том, что BOOST_ASSERT_MSG
по умолчанию требует char const *
, поэтому он несовместим.
Есть ли способ переопределить/перегрузить assertion_failed_msg()
таким образом, что использование потока как сообщения будет работать? Как?
(Мой наивный подход потерпел неудачу, поскольку компилятор сначала захотел сделать operator<<("foo",bar)
в самом сообщении...)
Вы можете определить свой собственный макрос
#define ASSERT_WITH_MSG(cond, msg) do \
{ if (!(cond)) { std::ostringstream str; str << msg; std::cerr << str.str(); std::abort(); } \
} while(0)
Это относительно тривиально для достижения этого.
BOOST_ASSERT_MSG( length >= 0, (std::stringstream() << "No positive length found! It is " << length).str().c_str() )
Я использую BOOST_ASSERT_MSG
с моей собственной оболочкой вокруг него, так что указание сообщения assert с несколькими operator<<
кажется менее сложным.
#if defined ASSERT_ENABLED
#define ASSERT(cond, msg) {\
if(!(cond))\
{\
std::stringstream str;\
str << msg;\
BOOST_ASSERT_MSG(cond, str.str().c_str());\
}\
}
#else
#define ASSERT(...)
#endif
укажите настраиваемое сообщение, которое вы выводите на cout
:
ASSERT(execSize == (_oldSize - remaining), "execSize : " << execSize << ", _oldSize : " << _oldSize << ", remaining : " << remaining);
Что он делает, если ASSERT_ENABLED
определено, включите сообщения об утверждении. if(!(cond))
part - это оптимизация, которая позволяет избежать дорогостоящих операций с строкой, заданных параметром макроса msg
, если cond
- true
Вот решение, которое не зависит от макросов. Вместо этого он использует немного синтаксиса шаблонов и лямбда-выражений.
template<typename Fn>
void assert_fn( bool expr, Fn fn) {
if (!expr) {
fn();
abort();
}
}
Аргумент fn
может быть любым вызываемым.
Например, вы можете назвать это так:
assert_fn( a==b, [&](){ cout << "Assertion failed: a="<< a <<
" is different from but b=" << b << endl; } );
Преимущество состоит в том, что вывод состоит в том, что вы не вызываете abort явно, и вывод полностью настраивается. Этим преимуществом, конечно же, являются семь дополнительных символов шаблона лямбда-функции: [&](){}
)