|
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