
On Mon, Aug 16, 2010 at 3:24 AM, Paul Mensonides <pmenso57@comcast.net> wrote:
On 8/13/2010 7:52 AM, Lorenzo Caminiti wrote:
Hello all,
I asked this question before but received no answer: Is there any problem in using `BOOST_PP_UNARY()` to check if a token matches a predefined keyword as indicated by the code below?
The following `IS_PUBLIC(token)` macro expands to 1 if `token` is `public`, to 0 otherwise:
#define PUBLIC_public (1) #define IS_PUBLIC(token) BOOST_PP_IS_UNARY(BOOST_PP_CAT(PUBLIC_, token))
IS_PUBLIC(public) // Expand to 1. IS_PUBLIC(abc) // Expand to 0.
This works just fine on both GCC and MSVC. However, `BOOST_PP_UNARY()` is only part of Boost.Preprocessor private API because:
IS_PUBLIC(+) results in undefined behavior. More generally, the result of token-pasting must result in a single (preprocessing) token. So, for example, BOOST_PP_CAT(abc, 123) and BOOST_PP_CAT(+, +) are okay, but BOOST_PP_CAT(abc, 123.0) and BOOST_PP_CAT(+, -) are not. Similarly for what you have above which will work provided everything used as an argument is an identifier (there are no "keywords" to the preprocessor) or a pp-number that doesn't contain any decimal points.
Yes, I am aware of this "limitation". However, for my application it is not a problem to limit the argument of `IS_PUBLIC()` to pp-identifiers and pp-numbers with no decimal points (if interested, see "MY APPLICATION" below). 1) Out of curiosity, is there a way to implement `IS_PUBLIC()` (perhaps without using `BOOST_PP_CAT()`) so it does not have this limitation? (I could not think of any.) 2) Also, does the expansion of any of the following result in undefined behavior? (I don't think so...) IS_PUBLIC(public abc) // Expand to 1. IS_PUBLIC(public::) // Expand to 1. IS_PUBLIC(public(abc, ::)) // Expand to 1. IS_PUBLIC(public (abc) (yxz)) // Expand to 1. (My application relies on some of these expansions to work.) MY APPLICATION I am using `IS_PUBLIC()` and similar macros to program the preprocessor to *parse* a Boost.Preprocessor sequence of tokens that represents a function signature. For example: class c { public: void f(int x) const; // Usual function declaration. }; class c { PARSE_FUNCTION_DECL( // Equivalent declaration using pp-sequences. (public) (void) (f)( (int)(x) ) (const) ); }; The parser macro above can say "the signature sequence starts with `public` so this is a member function" at a preprocessor metaprogramming level and then expand to special code as a library might need to handle member functions. The parser macros can even do some basic syntax error checking -- for example, if `(const)` is specified as cv-qualifier at the end of the signature sequence of a non-member function, the parser macro can check that and expand to a compile-time error like `SYNTAX_ERROR_unexpected_cv_qualifier` (using `BOOST_MPL_ASSERT_MSG()`). Most of the tokens within C++ funciton signatures are composed of pp-idenfitiers such as the words `public`, `void`, `f`, etc. There are some exceptions like `,` to separate funciton parameters, `<`/`>` for templates, `:` for constructors' member initializers, etc. The grammar of my preprocessor parser macros requires the use of different tokens in these cases. For example, parenthesis `(`/`)` are used for templates instead of `<`/`>`: template< typename T > f(T x); // Usual. PARSE_FUNCTION_DECL( // PP-sequence. (template)( (typename)(T) ) (f)( (T)(x) ) ); (Instead of `(template)(<) (typename) (T) (>) (f)( (T)(x) )` which will have caused the parser macro to fail when inspecting `(<)` via one of the `IS_XXX()` macros as per the limitation from using `BOOST_PP_CAT()` mentioned above.) The grammar of my preprocessor parser macros clearly documents that only pp-identifiers can be passed as tokens of the function signature sequence. Therefore, the "limitation" of `IS_PUBLIC()` indicated above is not a problem for my application. Thank you very much. -- Lorenzo