
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. 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();) \ ) \ ) As you can see in the above definition, I've included an explicit "false" clause for BOOST_PP_IIF() that expands into the harmless (and utterly superfluous) expression "static void PP_NILFUNC();". I would instead have preferred to use 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. Can this be fixed? -Brent

"Arias Brent-P96059" <Brent.Arias@gdds.com> writes:
As you can see in the above definition, I've included an explicit "false" clause for BOOST_PP_IIF() that expands into the harmless (and utterly superfluous) expression "static void PP_NILFUNC();". I would instead have preferred to use 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.
Can this be fixed?
I seriously doubt it. The fact that you can't represent an empty SEQ is a known limitation that Paul would have avoided had it been possible. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

-----Original Message----- [mailto:boost-bounces@lists.boost.org] On Behalf Of David Abrahams
Can this be fixed?
I seriously doubt it. The fact that you can't represent an empty SEQ is a known limitation that Paul would have avoided had it been possible.
It *is* possible, but the solution is undesirable. Such a thing as a nil sequence exists conceptually as an empty sequence of preprocessing tokens. We don't yet have the means to pass that around in C++. The way to do it is to make (e.g.) NIL symbolically represent a nil sequence. However, that functionality, which is only a temporary hack, produces other limitations. Nor would it help in Brent's situation. In fact, the hack would interfere even more because it destroys the ability to append sequences simply by placing them adjacently. E.g. if 'seq' is "(a)" then "(HEAD(seq)) TAIL(seq)" != 'seq'. Rather, it is "(a) NIL". Dealing with this situation requires an awful lot of NIL-checking. (Allowing benign NIL symbols in the middle of sequences would be *way* worse.) On the contrary, true nil sequences (ala C99) suffer none of those problems. Thus, without placemarkers (empty arguments) I had to choose between two evils. The choice was made to live with the limitation until we have the real thing. Regards, Paul Mensonides

-----Original Message----- [mailto:boost-bounces@lists.boost.org] 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
participants (3)
-
Arias Brent-P96059
-
David Abrahams
-
Paul Mensonides