Часто каждый хочет распечатать дополнительную информацию если assert
сбои. Способ сделать, который является этим:
assert(vec.size() > i ||
!(std::cerr << "False: " << vec.size() << ">" << i))
Таким образом, фактические размеры печатаются когда assert
сбои. Но это ужасно, и также легко забыть !
, который сделает условие утверждения верным, и программа только продолжится.
Что люди используют вместо этого для печати дополнительной информации об отказе утверждения, как вышеупомянутый?
Что люди используют вместо дополнительной информации об ошибке утверждения , как указано выше?
Обычно я ' d просто добавьте строковый литерал, описывающий значение условия:
assert(v.size() > i && "The vector really needs to be larger");
Но, возможно, такой макрос:
#include <cassert>
#include <vector>
#include <iostream>
//#define NDEBUG
#ifndef NDEBUG
#define ASSERT_EX(condition, statement) \
do { \
if (!(condition)) { statement; assert(condition); } \
} while (false)
#else
#define ASSERT_EX(condition, statement) ((void)0)
#endif
int main()
{
std::vector<int> v;
unsigned i = 1;
ASSERT_EX(v.size() > i, std::cerr << "i = " << i << ", v.size() = " << v.size() << '\n');
}
Здесь было бы неплохо, если бы оператор
не имел побочных эффектов, изменение способа оценки условия
. :)
assert () не компилируется в сборку Release многих компиляторов. Это не то, что имеет значение для производственного кода.
Я использую такую конструкцию:
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <ctime>
#include <iostream>
using namespace std;
template<typename T> inline bool Verify(T const& t,char const* Expression, char const* File, unsigned long Line)
{
bool b = !(!t);
if( b )
return true;
// verify failed -- report it
std::cerr << "Assertion '" << Expression << "' Failed @ " << File << ":" << Line << endl;
return false;
};
#define verify(exp) (bool)( Verify(exp, #exp, __FILE__, __LINE__) )
template<typename Iter> void doit(Iter const begin, const Iter & end)
{
for( ; begin != end; ++begin )
;
}
int main()
{
int n = 1;
n *= 2;
verify( n == 3 );
return 0;
}
Assertion 'n == 3' Failed @ .\main.cpp:32
Вот что я использую: разрывы на самой строке, где произошел сбой, а не где-либо еще в стеке. Работает на MSVC и GCC, использует небольшую магию ускорения и генерирует диалоговое окно подтверждения:
#include <boost/current_function.hpp>
#if defined(NDEBUG)
# define MY_ASSERT(expr) ((void)0)
#else
int assertion_failed(char const *expr, char const *function, char const *file, long line);
# if defined(_WIN32)
# define debugbreak __debugbreak
# else
# define debugbreak __builtin_trap
# endif
# define MY_ASSERT(expr) ((expr) || !assertion_failed(#expr, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__) || (debugbreak(), 0))
#endif
#if !defined(NDEBUG)
int assertion_failed(char const *expr, char const *function, char const *file, long line)
{
#if defined(_WIN32)
return ::_CrtDbgReport(_CRT_ASSERT, file, line, NULL, "%s", expr);
# else
return !0;
# endif
}
#endif
Если в качестве атрибута типа раздела указан NameGroupSureHandler
, а в качестве возвращаемого типа вызывается Configation.GetSection (последовательность)
, будет получен экземпляр DefureSection
.
последовательность SureInformation.SureInformation.GetRawXml ()
является ключом в данном случае для доступа к данным.
Я ответил на другой аналогичный вопрос с действительным путем сделать это с помощью System.Configuration
, на который можно сослаться, чтобы получить все подробности и фрагмент кода.
Для обратной записи в приложение
можно использовать этот тип раздела.
Начиная с этого кода.
def foo(
flab_nickers, # a series of under garments to process
has_polka_dots=False,
needs_pressing=False # Whether the list of garments should all be pressed
):
...
Я бы написал синтаксический анализатор, который захватывает определения параметров функции и строит следующее:
def foo(
flab_nickers,
has_polka_dots=False,
needs_pressing=False,
):
"""foo
:param flab_nickers: a series of under garments to process
:type flab_nickers: list or tuple
:param has_polka_dots: default False
:type has_polka_dots: bool
:param needs_pressing: default False, Whether the list of garments should all be pressed
:type needs_pressing: bool
"""
...
Это довольно прямая regex обработка различных аргументов строки, узоров для заполнения шаблона документации.
Множество хороших IDE Python (например, PyCharm) понимают обозначение Sphinx param
по умолчанию и даже флаги vars/methods в области, которая, по мнению IDE, не соответствует объявленному типу.
Запишите дополнительную запятую в коде; это просто для того, чтобы сделать все последовательным. Это не причиняет вреда, и это может упростить вещи в будущем.
Вы также можете попробовать использовать компилятор Python, чтобы получить дерево синтаксического анализа, пересмотреть его и создать код обновления. Я сделал это для других языков (не Python), так что я знаю немного об этом, но не знаю, насколько хорошо он поддерживается в Python.
Кроме того, это разовое преобразование.
Оригинальные строчные комментарии в определении функции на самом деле не следуют за DRY, потому что это комментарий, на неформальном языке и непригодный для использования любыми, кроме самых сложных инструментов.
Комментарии Sphinx ближе к DRY, поскольку они находятся на языке разметки RST, что значительно упрощает их обработку с помощью обычных инструментов разбора текста в docutils
.
Это только DRY, если инструменты могут использовать его.
Полезные ссылки: https://pythonhosted.org/an_example_pypi_project/sphinx.html#function-definitions http://sphinx-doc.org/domains.html#id1
-121--2980857- Я использую инструкцию if
или wxASSERT_MSG из wxWidgets .
Если вы используете рамку, посмотрите, предоставляет ли он некоторые полезные инструменты утверждения.
#define ASSERT(condition) { if(!(condition)){ std::cerr << "ASSERT FAILED: " << #condition << " @ " << __FILE__ << " (" << __LINE__ << ")" << std::endl; } }
Использование:
ASSERT(vec.size()>1);
Результат:
ASSERT FAILED: vec.size()>1 @ main.cpp (17)
В зависимости от ваших потребностей вы можете поместить DebugBreak()
или exit(-1)
или watever в макрос.
Обновленный макрос с раздельными левой и правой сторонами:
#define ASSERT(left,operator,right) { if(!((left) operator (right))){ std::cerr << "ASSERT FAILED: " << #left << #operator << #right << " @ " << __FILE__ << " (" << __LINE__ << "). " << #left << "=" << (left) << "; " << #right << "=" << (right) << std::endl; } }
Использование:
ASSERT(a,>,b);
Результат:
ASSERT FAILED: a>b @ assert2.cpp (8). a=3; b=4
Думаю, следующее имеет смысл. Вместо этого:
assert(vec.size() > i ||
!(std::cerr << "False: " << vec.size() << ">" << i))
просто сделайте следующее:
assert(vec.size() > i ||
assert_msg(vec.size() << ">" << i));
где assert_msg
определяется примерно так:
#define assert_msg(x) !(std::cerr << "Assertion failed: " << x << std::endl)
Наиболее расширенные обработчики утверждений имеют форму:
assert_x(CONDITION,EXPLANATION);
вам нужно что-то вроде
assert_args(condition, explanation, ...);
Итак:
extern string build_assert_string(const string&, explanation, ...);
#define ASSERT_ARGS(CONDITION,build_assert_string EXPLANATION)
вызовите как:
ASSERT_ARGS(x > 0, ("x should be > 0 but it is %d", x));
Функция build_assert_string проста.
Я использую нечто подобное:
#define ASSERT(lhs, op, rhs) assert_template((lhs##op##rhs), "(" #lhs #op #rhs ")", lhs, rhs, __FILE__, __LINE__)
template <typename t1, typename t2>
void assert_template(const bool result, const char expr[], t1 lhs, t2 rhs, const char file_name[], const long line_number)
{
if (!result)
{
std::cerr << "Assertion failed";
std::cerr << " " << expr;
std::cerr << " lhs = " << lhs;
std::cerr << " rhs = " << rhs;
std::cerr << " File: \"" << file_name << "\"";
std::cerr << " Line: " << std::dec << line_number;
throw "Assertion failed";
}
};
Синтаксис использования немного странный, как в ASSERT(vec.size(), >, 1)
или ASSERT(error, ==, 0)
. Положительным моментом является то, что он также выводит на печать значения с левой и правой стороны. На Windows мне также нравится бросать в GetLastError() и WSAGetLastError().