
-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Arkadiy Vertleyb
This will work on most preprocessors, but not on those that use the Borland configuration. Thanks to Daniel James, I do have a workaround for that bug for Borland in particular, but I don't have verification that it works on other preprocessors that use that configuration (so it has to wait until I can separate the implementations).
This definitely has a benefit of not having to provide multiple defines (but rather rely on ones in the Boost.Preprocessor). However, it uses some internal feature, IS_UNARY, which I guess is not a huge drawback since the suggestion comes from the author :-)
It would be a public interface if I could make it work across all supported preprocessors. That might be the case now, but I don't have access to either Sun's or IBM's preprocessors--both of which use the Borland configuration. The predicate definition itself is pretty straightforward if you take away the workarounds: #define CAT(a, b) PRIMITIVE_CAT(a, b) #define PRIMITIVE_CAT(a, b) a ## b #define SPLIT(i, im) PRIMITIVE_CAT(SPLIT_, i)(im) #define SPLIT_0(a, b) a #define SPLIT_1(a, b) b #define IS_NULLARY(x) \ SPLIT(0, CAT(IS_NULLARY_R_, IS_NULLARY_C x)) \ /**/ #define IS_NULLARY_C() 1 #define IS_NULLARY_R_1 1, ~ #define IS_NULLARY_R_IS_NULLARY_C 0, ~ #define IS_UNARY(x) IS_NULLARY(IS_UNARY_C x) #define IS_UNARY_C(a) () #define IS_BINARY(x) IS_NULLARY(IS_BINARY_C x) #define IS_BINARY_C(a, b) () #define IS_TERNARY(x) IS_NULLARY(IS_TERNARY_C x) #define IS_TERNARY_C(a, b, c) () // etc. The library already includes these macros complete with a mess of workarounds. However, the library doesn't yet contain a Borland compatible version--credits for this one go to Daniel James: #include <boost/preprocessor/detail/split.hpp> #include <boost/preprocessor/punctuation/comma.hpp> #include <boost/preprocessor/punctuation/paren.hpp> #include <boost/preprocessor/tuple/eat.hpp> #define IS_NULLARY(x) \ IS_NULLARY_2(BOOST_PP_SPLIT(1, IS_NULLARY_C x BOOST_PP_COMMA() 0)) \ /**/ #define IS_NULLARY_2(x) x #define IS_NULLARY_C() \ ~, 1 BOOST_PP_RPAREN() \ BOOST_PP_TUPLE_EAT(2) BOOST_PP_LPAREN() ~ \ /**/ #define IS_UNARY(x) IS_NULLARY(IS_UNARY_C x) #define IS_UNARY_C(a) () This should work on Borland's preprocessor, but I can't speak for Sun or IBM.
The portability issue is somewhat of concern -- I would not like to compromise it because of this nicety feature...
Do you think my other suggestion might be more portable?
#define TRANSLATE(x) BOOST_PP_SEQ_CAT(\ (STEP3)\ (BOOST_PP_CAT(STEP2, BOOST_PP_EXPAND(STEP1 x))) ^^^^^^^
The main thing that the Borland configuration works around is this situation. If 'x' is not parenthetic (i.e. the argument list to STEP1), the Borland preprocessor "merges" it similar to token-pasting, but (if I remember correctly) it does so without the possibility of constructing a macro name. E.g. #define A(args) B args #define B(a, b) a + b A( 1 ) -> B1 A( (x, y) ) -> x + y Daniel's version above, effectively just doesn't care that it is doing that or not. It works by shifting the parameters when the "attempt-to-expand" macro actually does invoke. I think that you're best course of action is to use the library's IS_UNARY, but define you're own IS_UNARY for Borland (as above). If you're concerned with supporting IBM and Sun, then you can fall back on macro replication and undefined behavior (concatenation to left-parethesis) because you're dealing with a finite set of possible inputs (i.e. numbers). I don't think that it is possible to use a single implementation that will work on all preprocessors. Note that kind of stuff tends to occur whenever you get into this kind of low-level detection stuff. For example, the automatic recursion in the library does a similar thing. For most preprocessor's that merely means attempting to invoke a macro (where success will produce a particular detectable output). When the particular macro doesn't expand, it is detected, so the mechanism moves on to the next one (technically speaking, it doesn't move on to the "next" one, it does a binary search). The Borland configuration, OTOH, cannot do this because (at the time) I didn't have an IS_NULLARY (or similar) that I could use to test whether a macro expanded. Without it, instead of testing for whether the result is X or not X, I have to test whether the result is X or Y or Z (and so on). IOW, I have to have literally *thousands* of extra macros just for that configuration. Now, I do have an IS_NULLARY implementation that will work on Borland, but other preprocessors (namely IBM and Sun) are using that configuration. Having those predicates is so useful that it is worth having an additional configuration (and all that that implies) for Borland. I haven't done that yet because I'm looking at quite a few more drastic changes (like unifying library state) as well as "preparing" the library for variadics (etc.). Regards, Paul Mensonides