
I came up with this great macro called IS_UNSIGNED_CHAR() such that IS_UNSIGNED_CHAR(unsigned char) expands to 1 and IS_UNSIGNED_CHAR(hello world) or any other input, expands to 0. It almost works, but it gets confused by IS_UNSIGNED_CHAR(unsigned world) which expands to garbage: BOOST_PP_IIF_I, EQUALS_42_57, RETURN_0)((42) world_U_I_O_P)); Any suggestions? Here is the code: #include <boost/preprocessor.hpp> #define Q_W_E_R_T_Y_unsigned 42) #define char_U_I_O_P (57 // Transmogrify t #define MOG(t) Q_W_E_R_T_Y_ ## t ## _U_I_O_P // Check if t is (42)(57) #define EQUALS_42_57(t) BOOST_PP_AND(BOOST_PP_EQUAL(42,BOOST_PP_SEQ_ELEM(0, t)), \ BOOST_PP_EQUAL(57,BOOST_PP_SEQ_ELEM(1, t)) ) // return 0 #define RETURN_0(t) 0 #define IS_UNSIGNED_CHAR(t) BOOST_PP_IIF(BOOST_PP_EQUAL(2,BOOST_PP_SEQ_SIZE((MOG(t)))), \ EQUALS_42_57, RETURN_0)((MOG(t))) // Here is some test data: IS_UNSIGNED_CHAR(unsigned char); // should expand to 1 IS_UNSIGNED_CHAR(hello world); // should expand to 0 IS_UNSIGNED_CHAR(unsigned world); // should expand to 0

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Edward Bishop
I came up with this great macro called IS_UNSIGNED_CHAR() such that
IS_UNSIGNED_CHAR(unsigned char)
expands to 1 and
IS_UNSIGNED_CHAR(hello world)
or any other input, expands to 0.
Any other identifier or (non-floating-point) pp-number input. You cannot pass something like '+' because the concatenation yields undefined behavior.
It almost works, but it gets confused by
IS_UNSIGNED_CHAR(unsigned world)
which expands to garbage: BOOST_PP_IIF_I, EQUALS_42_57, RETURN_0)((42) world_U_I_O_P));
It doesn't just expand to garbage, it is an error (not enough arguments to a macro). The problem is that your solution is generating half-open parenthesis if the input is two identifiers that is not 'unsigned char' but starts with 'unsigned' or ends with 'char'. The macro similarly doesn't work with something like 'unsigned abc char'.
Any suggestions? Here is the code:
Are you trying to detect 'unsigned char' specifically, or are you ultimately trying to compare strings of identifiers (keywords are identifiers here)? Regards, Paul Mensonides

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Paul Mensonides
Any suggestions? Here is the code:
Are you trying to detect 'unsigned char' specifically, or are you ultimately trying to compare strings of identifiers (keywords are identifiers here)?
Here's a more robust implementation of the former: #include <boost/preprocessor/cat.hpp> #include <boost/preprocessor/control/iif.hpp> #include <boost/preprocessor/detail/is_nullary.hpp> #include <boost/preprocessor/facilities/empty.hpp> #include <boost/preprocessor/facilities/expand.hpp> #include <boost/preprocessor/tuple/eat.hpp> #define IS_UNSIGNED_CHAR(x) \ BOOST_PP_IIF( \ BOOST_PP_IS_NULLARY( \ BOOST_PP_CAT(UNSIGNED_, x) \ ), \ BOOST_PP_IIF( \ BOOST_PP_IS_NULLARY( \ BOOST_PP_EXPAND(BOOST_PP_EMPTY BOOST_PP_CAT(UNSIGNED_, x))() \ ), \ 0 BOOST_PP_TUPLE_EAT(1), IS_UNSIGNED_CHAR_II \ ), \ 0 BOOST_PP_TUPLE_EAT(1) \ )(BOOST_PP_EMPTY BOOST_PP_CAT(UNSIGNED_, x)) \ /**/ #define IS_UNSIGNED_CHAR_II(x) \ BOOST_PP_IIF( \ BOOST_PP_IS_NULLARY( \ BOOST_PP_CAT(CHAR_, x) \ ), \ BOOST_PP_IS_NULLARY, 0 BOOST_PP_TUPLE_EAT(1) \ )(BOOST_PP_EXPAND(BOOST_PP_EMPTY BOOST_PP_CAT(CHAR_, x))()) \ /**/ #define UNSIGNED_unsigned () #define CHAR_char () Regards, Paul Mensonides

Are you trying to detect 'unsigned char' specifically, or are you ultimately trying to compare strings of identifiers (keywords are identifiers here)?
The IS_UNSIGNED_CHAR() macro is meant to be used in another macro: #define IS_BUILTIN_TYPE(x) BOOST_PP_OR(IS_UNSIGNED_CHAR(x), ...
Here's a more robust implementation of the former:
Thanks, that is extremely helpful, especially because it teaches me more about boost::preprocessor. All the best, Edward

Edward Bishop wrote:
Are you trying to detect 'unsigned char' specifically, or are you ultimately trying to compare strings of identifiers (keywords are identifiers here)?
The IS_UNSIGNED_CHAR() macro is meant to be used in another macro:
#define IS_BUILTIN_TYPE(x) BOOST_PP_OR(IS_UNSIGNED_CHAR(x), ...
But wouldn't it be more appropriate to do that at the type level so you can take into account typedefs? Andrei

The IS_UNSIGNED_CHAR() macro is meant to be used in another macro:
#define IS_BUILTIN_TYPE(x) BOOST_PP_OR(IS_UNSIGNED_CHAR(x), ...
But wouldn't it be more appropriate to do that at the type level so you can take into account typedefs?
Yes, but for the challange and the learning experience I'm trying to do it just using the preprocessor.

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Edward Bishop
The IS_UNSIGNED_CHAR() macro is meant to be used in another macro:
#define IS_BUILTIN_TYPE(x) BOOST_PP_OR(IS_UNSIGNED_CHAR(x), ...
But wouldn't it be more appropriate to do that at the type level so you can take into account typedefs?
Yes, but for the challange and the learning experience I'm trying to do it just using the preprocessor.
I was about to say the same thing as Andrei, but I didn't have time to get back to it yet. The preprocessor is good a certain things. Type manipulation is not one of them. Templates are much better at that. However, the preprocessor is good at (for example) generating instances of a patterns over a set of types. An 'is-builtin-type' predicate as a macro raises flags. It is one thing to generate, e.g., template specializations that together act as an 'is-builtin-type' facility. Doing so increases the level of abstraction by making a code pattern explicit. Doing actual type manipulation is fraught with problems and is almost always better done with core language features. As Andrei mentions, typedefs introduce a problem (lack of extensibility). Similarly (for something like the above), you have to handle all possible synonyms resulting from combinations (e.g. unsigned char == char unsigned). I recognize the desire to learn how to use the preprocessor, but part of that is learning where the use of the preprocessor is better and when it isn't. For the sake of argument, say you're going to do the above just for fun or as a learning tool. The approach that I described doesn't scale (even to just the built-in types). The code required would be so bloated that it would be easier to manually write a bunch of template specializations. If you were going to do something like this generally, a better approach would be to split words into single characters and compare strings of characters. Regards, Paul Mensonides

Paul Mensonides writes:
For the sake of argument, say you're going to do the above just for fun or as a learning tool. The approach that I described doesn't scale (even to just the built-in types). The code required would be so bloated that it would be easier to manually write a bunch of template specializations. If you were going to do something like this generally, a better approach would be to split words into single characters and compare strings of characters.
Is it implementable? -- Aleksey Gurtovoy MetaCommunications Engineering

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Aleksey Gurtovoy
Paul Mensonides writes:
so bloated that it would be easier to manually write a bunch of template specializations. If you were going to do something like this generally, a better approach would be to split words into single characters and compare strings of characters.
Is it implementable?
Sorry for the late reply; I've been busy. It is implementable with some sort of (minimal) registration. Regards, Paul Mensonides

Paul Mensonides writes:
so bloated that it would be easier to manually write a bunch of template specializations. If you were going to do something like this generally, a better approach would be to split words into single characters and compare strings of characters.
Is it implementable?
Sorry for the late reply; I've been busy.
No problem at all.
It is implementable with some sort of (minimal) registration.
I'd love to see somebody to tackle it, then :). I recall wanting it a couple of times. May be you could put up a Wiki page enumerating fun/challenging PP projects for people to pick up? -- Aleksey Gurtovoy MetaCommunications Engineering

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Aleksey Gurtovoy
It is implementable with some sort of (minimal) registration.
I'd love to see somebody to tackle it, then :). I recall wanting it a couple of times. May be you could put up a Wiki page enumerating fun/challenging PP projects for people to pick up?
Chaos already has a "string" data type that is made up of letters, numerals, or underscores. I just added a couple primitives that compare two strings for equality (one of them is case-insensitive). The library doesn't, OTOH, have a facility for translating a string of words into a string of characters, but doing that isn't all that hard (the attached file does it). What is hard, as usual, is getting it to work on buggy preprocessors. Regards, Paul Mensonides
participants (4)
-
Aleksey Gurtovoy
-
Andrei Alexandrescu (See Website For Email)
-
Edward Bishop
-
Paul Mensonides