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