Boost logo

Boost :

From: John Torjo (john_at_[hidden])
Date: 2003-05-02 02:32:05


> [from Samuel Krempp]
> But the same facility would be very useful for programmer errors too, as
> a way to state algorithm invariants with minimal overhead and
> comfortable formatting abilities, like a nice, extended, assert.
> BTW this is what the original thread was about, with John Torjo's
> SMART_ASSERT macro.
> (Of course, when a program fails an assertion, a core has all the
> information you can dream of. But I still like to get a good error
> message with the values of the interesting variables even before
> launching the debugger, as it is often enough to understand what is
> wrong. So I'm as intersted as John in a good way to enhance the basic
> assert macro)

Thanks. I'll try to provide a more detailed solution next week.

>
>
> In the context of a boost proposal of this Enforce thing, I think it
> would be good to simply provide 2 different macro names to address those
> 2 slightly distinct needs, e.g. ENFORCE and INVARIANT. (or THROWIF and
> ABORTIF, or whatever sounds self-explaining)
>
> of course both facilities would be very similar, but the distinguished
> names would stress the 2 different types of error checkings, and that
> seems to be an important point.
>
>
> In fac, with a suitable defintion of a
>
> struct DefaultAborter;
>
> inside which a throw(..) function prints a message and aborts, INVARIANT
> could simply be defined by :
>
> #define INVARIANT(exp) \
> *MakeEnforcer<DefaultPredicate, DefaultAborter>(\
> (exp), "Expression '" #exp "' failed in '" \
> __FILE__ "', line: " STRINGIZE(__LINE__))
>
>
> now we get an alternative to John Torjo's smart_assert :
>
> > assert( (i < j) || (i == 0) || (j == 1) ); would change into
> > SMART_ASSERT( (v_(i) < v_(j)) || (i == 0) || (j == 1) );
>
> INVARIANT( (i < j) || (i == 0) || (j == 1)) (i) (j) ;
>

This would look incredibly cool!
However, I spent some time, and I don't know how to implement it.

This is basically because (in my version),
when you say v_(i), it transparently does something like
log_information( i, #i); this is how it can actually output something like
'i = 5'.

However, just using (i) (j) I'm not sure we can do this. I may be wrong, but
this should not work:

#define OP1(x) std::cout << #x << "=" << (x) << std::endl;
#define OP2(x) std::cout << #x << "=" << (x) << std::endl; OP1

Then, the question is, will 'OP2(i)(j)' output the values of i and j?
By my reading of the standard, I think not. But I'm not sure.
The funny thing is that I tried the following example:
------------
#include <string>
#include <iostream>

#define OP1(x) std::cout << #x << "=" << (x) << std::endl;
#define OP2(x) std::cout << #x << "=" << (x) << std::endl; OP1

int main()
{
    int i = 1, j =2;
    OP2(i)(j);
    std::cin.get();
}
------------
, and it works with VC6, gcc3.2 and it compiles with Comeau. So, it must be
ok.

In this case, I think somehow we can implement your suggestion with (i) (j).
It would be truly great!

Best,
John


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk