Boost logo

Boost :

From: Darin Adler (darin_at_[hidden])
Date: 2000-02-10 12:07:30


> I've heard various mentions in the past (here?) about implementing compile
> time assertions and wondered if anyone had considered implementing them for
> boost as part of a general debugging section to the library.

There were a number of messages about this last December, including a sample
implementation. Check out
<http://www.egroups.com/MessagesPage?method=performAction&listName=boost&sea
rch=ctassert> to see them.

In my past attempts to create a compile-time assertion implementation (I
used the name postulate for mine), I've never been able to create an
implementation that fulfills all the 5 requirements suggested by Csaba
Szepesvari in December 1999:

    (R1) Give an error message *at the line* where the assertion fails.
    (R2) Usable in both declarations and implementations in the same way.
    (R3) No real code should be generated and no storage should be used.
    (R4) No macros.
    (R5) Namespaces should be polluted in a minimal way.

Here's a cut at the requirements I came up with back in February 1999.

     1) no runtime cost: Using it has no cost or effect on the program other
than preventing it from compiling -- it doesn't change optimizations, sizes
of structures, or anything like that.
     2) use anywhere: It can be used inside a function definition or outside
a function definition, inside a structure (or class) declaration or outside
a structure declaration.
     3) simple syntax: It can be called in the same simple way that assert
can be.
     4) can use compile-time constants: It can use anything that the
compiler can figure out at compile time, using the same rules as those for
array sizes, for example, not the more-restrictive rules of the
preprocessor.
     5) stop with error: With a false expression it will prevent the program
from compiling, causing an an error.
     6) portable: It will work as described above on any conforming
implementation (uses only things in the standard).
     7) good error message: The error message will be easy to understand on
any implementation.
     8) points to correct line: The line that the compiler reports an error
on will be the line of the statement on any implementation.
     9) practical: It will work as described above on currently available
implementations.

Jay Zipnick has a page about this subject at
<http://www.best.com/pub/~jayz/C++/Postulate.html>. I'm not sure Jay has
ever publicized it.

One of the most practical implementations I ever encountered was the one
marked E below:

  #define POSTULATE(condition) struct { int : (condition) ? 0 : -1; }

But it still doesn't work for this case:

    struct X {
        void test();
        int member;
    };

    void X::test()
    {
        POSTULATE(sizeof(member) == 4);
    }

Here are some implementations I have tried, with some of the problems of
each implementation listed (but by no means all):

A (Brian Fitzgerald):

    #define POSTULATE(condition) { \
        char A[1 - 2 * int(!(condition))]; \
        A[0]; \
    }

Problems: causes an unused variable warning under some compilers, can't be
used outside a function definition.

B (Brian Fitzgerald):

    #define POSTULATE(condition) { \
        const int failed = int(!(condition)); \
        struct { char A[1 - 2 * failed]; }; \
    }

Problems: can't be used outside a function definition, C++ only.

C (Darin Adler and Phil Goldman):

    #define POSTULATE_DECL(condition, id) \
        struct postulate_check_##id \
            { char negative_size_if_false[(condition)*2 - 1]; }
    #define POSTULATE(condition) \
        do { POSTULATE_DECL(condition, 1); } while (0)

Problems: two different macros for use inside and outside of function
declarations, postulate_decl macro requires second parameter with ID to
avoid name conflicts, postulate_decl macro will add padding if used in a
structure definition, can't use expression that refers to non-static members
of class if used within class definition or member function.

D (Jay Zipnick):

    #define POSTULATE(condition) struct { int a[(condition) ? 1 : -1]; }

Problems: will add padding if used in a structure definition, if condition
includes use of "a", will use the "a" from the structure, can't use
expression that refers to non-static members of class if used within class
definition or member function.

E (Jay Zipnick):

    #define POSTULATE(condition) struct { unsigned : (condition) ? 0 : -1; }

Problems: can't use expression that refers to non-static members of class if
used within class definition or member function, relies on non-standard
behavior.

F (Jay Zipnick and Nathan Myers):

    #define POSTULATE(condition) struct { unsigned int :-! (condition); }

Problems: can't use expression that refers to non-static members of class if
used within class definition or member function, relies on non-standard
behavior.

G (Jay Zipnick and Nathan Myers):

     template<bool condition>
     struct postulate { : (condition) ? 0 : -1; };

Problems: Only first instantiation must fail, error message may not point to
instantiation line, must define and name an object to use it.

H (Jay Zipnick and Nathan Myers):

    template<bool> struct bool_checker { typedef int int_if_true; };
    template<> struct bool_checker<false> { typedef void* int_if_true; };
    inline void postulate_helper(int) { }
    #define POSTULATE(condition) \
        postulate_helper(bool_checker<condition>::int_if_true)

Problems: Can't be used outside function definition.

Good luck finding an implementation polished enough to use in the Boost
library! I'd like to have this one.

    -- Darin


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