Are there non-macro assertions?

D

DeMarcus

Hi,

I would like to keep assertions but get rid of macros in my code.
Are there examples of the assert function built on templates?


Thanks,
Daniel
 
M

Michael Doubez

I would like to keep assertions but get rid of macros in my code.
Are there examples of the assert function built on templates?


If you want the exact replacement of assert(), you cannot: with NDEBUG
assert() will expand to nothing which mean that parameters will no be
evaluated.

Without macro, you cannot simply remove code. You can do somewhat
similar with a shortcut operator:
Assertion::assert( !Assertion::activated || /* assertion */ );

With
struct Assertion
{
static const bool activated = false;

//....
};

This is hideous.

Concerning getting __FILE__ and __LINE__, a template cannot get it
from the point it is called (because they are replaced by the
preprocessor).
 
D

DeMarcus

Leigh said:
if you want to do something other than call std::abort (for example
throw an exception) you could do:

template<class X, class A> inline void Assert(A assertion)
{
if (!assertion) throw X();
}

class Bad_arg {};

void f(int* p)
{
Assert<Bad_arg>(p != 0);
}

-- from Stroustrup (TC++PL)

/Leigh

Maybe it's irrational to avoid macros but I want to pass log messages in
the assertion, hence I need to write my own assert() anyway and thought
I could do it with a little inspiration from some other template assert.

The Stroustrup tip looks like something I could get ideas from.


Thanks!
Daniel
 
D

DeMarcus

Michael said:
If you want the exact replacement of assert(), you cannot: with NDEBUG
assert() will expand to nothing which mean that parameters will no be
evaluated.

Without macro, you cannot simply remove code. You can do somewhat
similar with a shortcut operator:
Assertion::assert( !Assertion::activated || /* assertion */ );

With
struct Assertion
{
static const bool activated = false;

//....
};

This is hideous.

Concerning getting __FILE__ and __LINE__, a template cannot get it
from the point it is called (because they are replaced by the
preprocessor).

Actually the reason why I want to write my own assert is to be able to
pass messages to a system log. I will actually write something similar
to the code you wrote. You are also completely right about the file and
line information, but I pass that on in the log massage today, so then
everything should be set.

As far as I understand, the only two reasons for assert() being a macro are:

* To provide __FILE__ and __LINE__ automatically.
* To save 1 nanosecond when disabling the assert(), having no code at
all compared to an if( assertionEnabled && !condition ).

Or are there more reasons?


Thanks,
Daniel
 
N

Nick Keighley

Actually the reason why I want to write my own assert is to be able to
pass messages to a system log. I will actually write something similar
to the code you wrote. You are also completely right about the file and
line information, but I pass that on in the log massage today, so then
everything should be set.

As far as I understand, the only two reasons for assert() being a macro are:

* To provide __FILE__ and __LINE__ automatically.
* To save 1 nanosecond when disabling the assert(), having no code at
all compared to an if( assertionEnabled && !condition ).

Or are there more reasons?

to expand the condition as part of the assertion message?

assert (x > 0);
=>
"assertion failed x > 0 pippo.c line: 42

how does a template get the "x > 0" into the string?

Rather hacky code:-

#define ASSERT_X(A) ((A) ? (void)0 \
: logger.throw_assert (__FILE__, __LINE__,
#A))


void Log::throw_assert (const char *file, int line, const char *msg)
{
fatal (file, line, "Assertion failed: %s", msg);
throw runtime_error ("Assertion failed");
}


in this code logger was a global error reporter (it was (almost) the
only global, honest!). fatal() wrote a suitable mmessage to the
logger. Looking again I'd have thrown std::logic_error

Why no _NDEBUG? Because I don't turn my asserts off! See another
thread :)
 
D

DeMarcus

Nick said:
to expand the condition as part of the assertion message?

assert (x > 0);
=>
"assertion failed x > 0 pippo.c line: 42

how does a template get the "x > 0" into the string?

I don't want to be rude, but that information is not useful anyway. You
have a failed assertion and go to line 42 in pippo.c. There you will see
(x > 0) anyway. What may be useful though, is if you could show the
value of x in the output, but that's not harder in a template than in an
assert().

For me, that don't like macros, I think that the only thing speaking for
the macro assert is the automatic insertion of __FILE__ and __LINE__.

Rather hacky code:-

#define ASSERT_X(A) ((A) ? (void)0 \
: logger.throw_assert (__FILE__, __LINE__,
#A))


void Log::throw_assert (const char *file, int line, const char *msg)
{
fatal (file, line, "Assertion failed: %s", msg);
throw runtime_error ("Assertion failed");
}


in this code logger was a global error reporter (it was (almost) the
only global, honest!). fatal() wrote a suitable mmessage to the
logger. Looking again I'd have thrown std::logic_error

Why no _NDEBUG? Because I don't turn my asserts off! See another
thread :)

I agree with you. I prefer to keep the asserts on all the time rather
than saving a couple of nanoseconds here and there.
 
J

Johannes Schaub (litb)

DeMarcus said:
Hi,

I would like to keep assertions but get rid of macros in my code.
Are there examples of the assert function built on templates?

I imagine you could do it with lambdas

template<typename T>
void assert(T t) { if(!t()) std::abort(); }

....

assert( [&]{ return foo && bar; });
 
I

Ian Collins

Hi,

I would like to keep assertions but get rid of macros in my code.
Are there examples of the assert function built on templates?

Assertions are one of the very few justifications for keep macros in C++
code. You simply can't duplicate their functionality by any other means.
 
J

John H.

As far as I understand, the only two reasons for assert() being a macro are:

* To provide __FILE__ and __LINE__ automatically.
* To save 1 nanosecond when disabling the assert(), having no code at
all compared to an if( assertionEnabled && !condition ).

Or are there more reasons?

At the risk of stating the obvious: a reason for a compiler to
implement assert as a macro is because the C++ standard states that it
is to be a macro. Which in turn is influenced by the C standard.

A reason why the C standard might have made it a macro is to allow its
behavior to be defined at the point where it is most recently
#included. For a traditional function call, the behavior is defined
when it is first #included. Here is an example:

#define NDEBUG
#include <cassert>
void func1()
{
assert(0);
}


#undef NDEBUG
#include <cassert>
void func2()
{
assert(0);
}

int main()
{
func1();
func2();
return 0;
}

Here, func1 does nothing because NDEBUG was defined when cassert was
#included. func2 will abort because NDEBUG was not defined when
cassert was #included the second time. If you tried to do this with
functions you might have more difficulty. For instance, trying to
#include <cassert> twice would cause build complaints because assert
is defined twice, or (if include guards are used in cassert) the
behavior would be fixed upon the first inclusion of cassert, and the
second inclusion would be a no-op.
We might have some clever ways to get around this with C++ features
(templates or lambdas) but they aren't available for C.
 
J

James Kanze

I would like to keep assertions but get rid of macros in my code.
Are there examples of the assert function built on templates?

The whole point of assert is that you can turn it off on a
function by function basis. This means that the implementation
must do #undef, before redefining it. And there's no way to
undef anything but a macro.

Also, good implementations of assert generally include a use of
__FILE__ and __LINE__. Which also requires a macro,
 
J

James Kanze

Actually the reason why I want to write my own assert is to be
able to pass messages to a system log.

In which case, you're not talking about assert, but something
else. (Which will probably involve macros as well, in order to
automatically insert __FILE__ and __LINE__.)

[...]
As far as I understand, the only two reasons for assert() being a macro are:
* To provide __FILE__ and __LINE__ automatically.
* To save 1 nanosecond when disabling the assert(), having no code at
all compared to an if( assertionEnabled && !condition ).
Or are there more reasons?

The main one is that you can turn it off on a function by
function basis, rather than only globally.
 
D

DeMarcus

Johannes said:
DeMarcus said:
Hi,

I would like to keep assertions but get rid of macros in my code.
Are there examples of the assert function built on templates?

I imagine you could do it with lambdas

template<typename T>
void assert(T t) { if(!t()) std::abort(); }

...

assert( [&]{ return foo && bar; });

Hm, that's an interesting solution. I'll think about it.

Thanks,
Daniel
 
M

Miles Bader

DeMarcus said:
I don't want to be rude, but that information is not useful anyway. You
have a failed assertion and go to line 42 in pippo.c. There you will see
(x > 0) anyway.

There are some reasons why seeing the expression is useful though:

(1) It makes it easier to locate the exact assertion if the code-base
has changed since the executable was made (especially useful when
there's a bunch of adjacent assertions).

(2) During development, the assertion expression is often immediately
recognizable to the programmer ("oh, it's the damn XXX problem again"),
and so can speed up debugging. [For commonly occurring problems, they
may recognize a filename / line number too, but it's probably easier
with an expression, especially if variables names etc are informative.]

-Miles
 
D

DeMarcus

Miles said:
DeMarcus said:
I don't want to be rude, but that information is not useful anyway. You
have a failed assertion and go to line 42 in pippo.c. There you will see
(x > 0) anyway.

There are some reasons why seeing the expression is useful though:

(1) It makes it easier to locate the exact assertion if the code-base
has changed since the executable was made (especially useful when
there's a bunch of adjacent assertions).

(2) During development, the assertion expression is often immediately
recognizable to the programmer ("oh, it's the damn XXX problem again"),
and so can speed up debugging. [For commonly occurring problems, they
may recognize a filename / line number too, but it's probably easier
with an expression, especially if variables names etc are informative.]

-Miles

Ok, I agree. You have a point there.
 
M

Michael Doubez

Having if( assertionEnabled && !condition ) is exactly the same as
assert() if assertionEnabled is a compile time constant (the compiler
will simply remove the code). But it is a bit tedious to repeat.


If you have the file and the line passed to the template, you also get
the content of the condition (you pass #condition in parameter ).

[snip]
 
S

subramanian100in

The whole point of assert is that you can turn it off on a
function by function basis. This means that the implementation
must do #undef, before redefining it. And there's no way to
undef anything but a macro.

Also, good implementations of assert generally include a use of
__FILE__ and __LINE__. Which also requires a macro,

Kindly give a code sample so that I can understand, regarding how to
turn off assert on a function by function basis.

Thanks
V.Subramanian
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,070
Latest member
BiogenixGummies

Latest Threads

Top