Boost logo

Boost :

Subject: Re: [boost] [Preprocessor] Adding variadic macros support
From: Paul Mensonides (pmenso57_at_[hidden])
Date: 2010-11-27 09:36:47


On Thu, 25 Nov 2010 08:42:37 -0500, Edward Diener wrote:

> You are right. Evidently the code is under CVS, but not under SVN ( yet
> ? ).
>
> I will look at Chaos and see what is done.

You'll have to pull it out of the CVS repository. The Subversion
respository is not being used yet. The library is complete, as of right
now there are more than five hundred primary interface macros (i.e. not
counting implementation macros). There are more than two thousand
interface macros if derivative macros are included (still not including
implementation macros).

If you checkout from the CVS, there is a file $CHAOS_ROOT/built-docs/
headers.html that lists all of the headers in the library. The first
link (i.e. <chaos/preprocessor.h>) might be more useful for navigation.
The reference documentation is complete (and extensive) except for a
couple of macros that I added recently. There are lots of examples
(mostly contrived). The topical documention is not complete, but feel
free to ask me whatever you want.

Chaos' use of variadics is controlled by CHAOS_PP_VARIADICS. This is
normally set automatically based on whether the language supports
variadics. However, there is currently no usable definition of
__cplusplus for it to work with. Thus, by default, variadics are
disabled in C++. However, the macro CHAOS_PP_VARIADICS can be defined on
the command line to override the automatic settings. E.g. with GCC...

g++ -E -P -std=c++0x -I $CHAOS_ROOT -D CHAOS_PP_VARIADICS test.cpp

===== Requirement for a Compliant Preprocessor =====

The techniques used by Chaos' internals are *extremely* advanced. Most
of the time, they require the preprocessor to do *exactly* what it should
do according to the standard(s). Because of that, Chaos cannot be ported
to broken preprocessors like MS (and putting workarounds in the source
would defeat the purpose of Chaos even if such workarounds were possible).

I believe that GCC, EDG-based compilers, and Wave are 100% usable. There
are a few others that are mostly usable as well as a few tools that have
internal (custom) preprocessor implementations that are 100% usable
also. In particular, VC++ is *not* usable. I am not sure about Sun at
the moment.

===== Notable Differences from the Boost pp-lib =====

The most obvious (considering the context) is support for variadics/
placemarkers from the ground up. Probably more importantly, Chaos
generalizes recursion and all higher-order constructs are reentrant
without replication of their implementations. As an example, take a look
at the implementation of BOOST_PP_REPEAT compared to the following:

#define REPEAT(n, macro, ...) \
    REPEAT_S(CHAOS_PP_STATE(), n, macro, __VA_ARGS__) \
    /**/
#define REPEAT_S(s, n, macro, ...) \
    CHAOS_PP_IF(n)( \
        REPEAT_I, CHAOS_PP_EAT \
    )( \
        CHAOS_PP_OBSTRUCT(), CHAOS_PP_NEXT(s), \
        CHAOS_PP_DEC(n), macro, __VA_ARGS__ \
    ) \
    /**/
#define REPEAT_INDIRECT() REPEAT_S
#define REPEAT_I(_, s, n, macro, ...) \
    CHAOS_PP_EXPR_S _(s)(REPEAT_INDIRECT _()( \
        s, n, macro, __VA_ARGS__ \
    )) \
    CHAOS_PP_CALL(macro)()(s, macro, n, __VA_ARGS__) \
    /**/

#define MACRO(s, n, ...) \
    CHAOS_PP_COMMA_IF(n) class T ## n \
    /**/

CHAOS_PP_EXPR(REPEAT(
    5, MACRO, ?
))

===== Variadics as Data Structures =====

Over the course of development of Chaos, I rapidly discovered that the
direct use of variadics as element sequences is only marginally useful
(at best). Variadics are better used for other things. Let me clarify.
Variadics as raw data structures are virulent. They take over the
interface of everything else by forcing particular argument orders and
"stealing" the single variadic "argument". As an obvious example, you
can't have an algorithm that operates on two such data structures.

OTOH, variadics used indirectly in data structures are very useful (e.g.
variadics sequences). Even with tuples such that the size is not
required to be known for element access. Long story short, (...) is
better than just ... for all kinds of reasons.

===== Lambdas/Binding =====

Chaos has a pretty heavyweight lambda engine. For example (contrived),

#include <chaos/preprocessor.h>

CHAOS_PP_EXPR(CHAOS_PP_ENUM(
    5,
    CHAOS_PP_PRIMITIVE_CAT_(class T, CHAOS_PP_ARG(1))
        CHAOS_PP_WHEN_(CHAOS_PP_ARG(1))(
            CHAOS_PP_CAT_(= T, CHAOS_PP_DEC_(CHAOS_PP_ARG(1)))
        )
))

...results in:

class T0, class T1 = T0, class T2 = T1, class T3 = T2, class T4 = T3

However, the problem with lambdas (with the preprocessor) is that they
are considerably more expensive. No matter how you do it, it requires
some sort of interpretation--which is slower--and simply having a macro
is usually clearer. I've actually been considering their removal from
Chaos for several years.

#define _(s, n) \
    class T ## n \
        CHAOS_PP_WHEN(n)(= CHAOS_PP_CAT(T, CHAOS_PP_DEC(n))) \
    /**/

CHAOS_PP_EXPR(CHAOS_PP_ENUM(5, _))

#undef _


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