Boost logo

Boost :

From: John Maddock (John_Maddock_at_[hidden])
Date: 2000-02-26 07:21:26


>Now, I have a question for anyone with the C standard, or for someone
>on the C++ committee who remembers making this change (if it was a
>change). Would this work for C? C:ARM says no; but it could be wrong,
>for all I know. There's no mention in [C.1] (Compatibility: C++ and
>ISO C) about this kind of a difference from C.

C99 says:
"1 After the arguments for the invocation of a function-like macro have
been identified,
argument substitution takes place. A parameter in the replacement list,
unless preceded
by a # or ## preprocessing token or followed by a ## preprocessing token
(see below), is
replaced by the corresponding argument after all macros contained therein
have been
expanded. Before being substituted, each arguments preprocessing tokens are
completely macro replaced as if they formed the rest of the preprocessing
file; no other
preprocessing tokens are available."

So I think that both C and C++ behave the same and the macro expansion as
we have it is correct.
For the VC6 problem see note (2) below.

Some further words are in order about the two suggested methods:

1) Function declaration method:
When I messed with this I tried something like:
#define BOOST_CT_ASSERT( B ) void BOOST_JOIN(name,
__LINE__)(::boost::ct_assert<(B)> b = ::boost::ct_assert<(B)>())

except that this doesn't work!

#define BOOST_CT_ASSERT(cond)\
  void BOOST_JOIN(_boost_postulate_details_, __LINE__)\
      (::boost::ct_assert<false>); \
  void BOOST_JOIN(_boost_postulate_details_, __LINE__)\
      (::boost::ct_assert<(cond)> = ::boost::ct_assert<true>())

Steve - when I looked (quickly) at your codeI thought that you were doing
the same as I was, having had a chance to try it some more I see that
actually your code works very well under C++ Builder, but I can't persuade
either gcc or VC6 to compile it - this looks like compiler bugs (again),
related to function scope function declarations.
There is another issue here - this method generates two function
declarations per assertion, object diagramming tools, and even some
debuggers will display these symbols - there's not much we can do about
this, but read on:

2) enum declaration method:
#define BOOST_CT_ASSERT( B ) enum { BOOST_JOIN(_boost_assert_enum_,
__LINE__) = sizeof(::boost::ct_assert< ( B ) >) }
Generates a single type declaration only, seems to be well supported under
several compilers - but under VC6 the -ZI option causes the code to choke -
as this is the default ide option this is a problem, in fact a really weird
problem - if the file is preprocessed first using /P/EP options it compiles
fine with -ZI, for some reason -ZI is screwing up the preprocessor.
This method generates one symbol per assertion - as with function
declarations these may show up in object diagramming tools, and some

3) typedef method:
This is a variation on (2), the code is:

namespace boost{

template <bool> struct ct_assert;

template <> struct ct_assert<true>{};

template<int> struct ct_assert_test{};


#define BOOST_CT_ASSERT( B )\
 typedef ::boost::ct_assert_test<sizeof(::boost::ct_assert< ( B ) >)>
BOOST_JOIN(_boost_postulate_details_, __LINE__)

#define BOOST_DO_JOIN( X, Y ) X ## Y
#define BOOST_JOIN( X, Y ) BOOST_DO_JOIN( X, Y )

In this case we define a single typedef - the error messages are
essentially the same as (2) - something like "Undefined type ct_assert<0>"
on most compilers. The advantage is that the typedefs when used at class
scope do not show up as symbolic constants in the debugger as (2) can. The
problem is that VC6 chokes on this at function scope (same problem as (2)).

I wonder if anyone has access to something like Rational Rose - it would be
interesting to know how these various methods are handled.

Finally, in the face of all these compiler problems - given that the
deffinitions are quite compact, we could have compiler specific versions
where required.

- John.

Boost list run by bdawes at, gregod at, cpdaniel at, john at