Boost logo

Boost :

From: Paul Mensonides (pmenso57_at_[hidden])
Date: 2004-11-19 01:38:44


> -----Original Message-----
> [mailto:boost-bounces_at_[hidden]] On Behalf Of Arias Brent-P96059

> I've invented a printable enum, based on the Boost
> preprocessor programming lib. But although the printable
> enum works, I think my efforts revealed a bug in Boost.

Not a bug. Empty macro arguments are currently undefined behavior in C++.
There is nothing that I can do about that. C99 added explicit support for them,
but they are not (yet) part of C++.

> The BOOST_PP_SEQ_ENUM preprocessor macro doesn't work with
> the empty "false"
> result of BOOST_PP_EXPR_IIF. This has forced me to do
> hacks like this:
>
> #define ENUM(name, start, entries)\
> BOOST_PP_SEQ_ENUM( \
> BOOST_PP_IIF(ENUMS, \
> (typedef enum{ BOOST_PP_SEQ_HEAD(entries) = start) \
> BOOST_PP_SEQ_TAIL(entries) \
> (LAST_##name } name;) \
> , \
> (static void PP_NILFUNC();) \
> ) \
> )

Why are you doing the test *inside* of the invocation of SEQ_ENUM? That is
roughly equivalent to doing something like:

#include <algorithm>
#include <iostream>
#include <vector>

void print(int x) {
    std::cout << x << ' ';
    return;
}

extern bool flag;

int main(int argc, char* argv[]) {
    int init[] = { 1, 2, 3, 4, 5 };
    std::vector<int> v(init, init + sizeof(init) / sizeof(int));
    std::for_each((flag ? v.begin() : v.end()), v.end(), &print);
                // ^^^^^^^^^^^^^^^^^^^^^^^^^^
    return 0;
}

Instead of:

if (flag) std::for_each(v.begin(), v.end(), &print);

The same thing applies at the preprocessor level--if you want to conditionally
enumerate a sequence, then invoke the enumeration primitive conditionally
instead of attempting to unilaterally enumerating a sequence while trying to
conditionally make that enumeration benign.

#include <boost/preprocessor/control/iif.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/preprocessor/seq/seq.hpp>
#include <boost/preprocessor/tuple/eat.hpp>

#define ENUM(name, start, entries) \
    BOOST_PP_IIF( \
        ENUMS, \
        BOOST_PP_SEQ_ENUM, BOOST_PP_TUPLE_EAT(1) \
    )( \
        (typedef enum { BOOST_PP_SEQ_HEAD(entries) = start) \
        BOOST_PP_SEQ_TAIL(entries) \
        (LAST_ ## name } name;) \
    ) \
    /**/

RANT: If preprocessors worked as they should, I could guarantee lazy semantics
in if-like constructs. With lazy semantics in this context, the above would be:

#define ENUM(name, start, entries) \
    BOOST_PP_EXPR_IIF(ENUMS)( \
        BOOST_PP_SEQ_ENUM( \
            (typedef enum { BOOST_PP_SEQ_HEAD(entries) = start) \
            BOOST_PP_SEQ_TAIL(entries) \
            (LAST_ ## name } name;) \
        ) \
    ) \
    /**/

> BOOST_PP_EXPR_IIF and thus avoid the eye-sore. But the hack
> was necessary, as I said before, because BOOST_PP_SEQ_ENUM
> does not elogantly handle the empty "false" result of
> BOOST_PP_EXPR_IIF.

C++ does not elegantly handle empty macro arguments. There is literally
*nothing* I can do about that.

Regards,
Paul Mensonides


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