When use ## in a macro to concat two parameters, I met a problem with some proprocessing tricks. The gcc doesn't allow it's result is not a valid preprocessing token, etc.
In most simple case, we can just remove it, but sometimes, when using the proprocessing macro as an meta progrmming language, it couldn't be ignored.
One of the example is from the preprocessor library from
boost.org, a undocument interface BOOST_PP_IS_EMPTY, which can be used to check whether a processing token empty or not, the code may be:
#include <boost/preprocessor/facilities/is_empty.hpp>
BOOST_PP_IS_EMPTY() /* result: 1 */
BOOST_PP_IS_EMPTY(a) /* result: 0 */
BOOST_PP_IS_EMPTY(+a) /* error report here, for '+' cannot be pasted */
For IS_EMPTY macro there is a workaround to avoid the problem, the definitions are:
#define MY_IS_EMPTY(a) BOOST_PP_EQUAL(BOOST_PP_SEQ_SIZE(MY_IS_EMPTY_II(MY_IS_EMPTY_I(MY_PAREN_DEL(a)))), 2)
#define MY_IS_EMPTY_I(a) (BOOST_PP_CAT(MY_IS_EMPTY_I_, BOOST_PP_SEQ_SIZE(a))) )
#define MY_IS_EMPTY_I_0 MY_IS_EMPTY_I_HELPER BOOST_PP_LPAREN()
#define MY_IS_EMPTY_I_HELPER(a) )a( /* when a is empty, my may get more sequence elements of boost proprocessor */
#define MY_IS_EMPTY_II(a) BOOST_PP_CAT(MY_IS_EMPTY_II_, BOOST_PP_SEQ_SIZE(a)) )
#define MY_IS_EMPTY_II_1 (
#define MY_IS_EMPTY_II_2 ()(
The MY_PAREN_DEL macro is used for removing any parenthneses around a parameter, maybe defined as:
#define MY_PAREN_DEL(a) BOOST_PP_CAT(MY_PAREN_DEF_, MY_PAREN_DEL_1 a)
#define MY_PAREN_DEL_1(a) MY_PAREN_DEL_2 a
#define MY_PAREN_DEL_2(a) MY_PAREN_DEL_3 a
#define MY_PAREN_DEL_3(a) MY_PAREN_DEL_4 a
#define MY_PAREN_DEL_4(a) MY_PAREN_DEL_5 a
#define MY_PAREN_DEL_5(a) MY_PAREN_DEL_6 a
...
#define MY_PAREN_DEF_MY_PAREN_DEL_1
#define MY_PAREN_DEF_MY_PAREN_DEL_2
#define MY_PAREN_DEF_MY_PAREN_DEL_3
#define MY_PAREN_DEF_MY_PAREN_DEL_4
#define MY_PAREN_DEF_MY_PAREN_DEL_5
#define MY_PAREN_DEF_MY_PAREN_DEL_6
...
Then we may get:
MY_IS_EMPTY() /* result 1 */
MY_IS_EMPTY(a) /* result 0 */
MY_IS_EMPTY(+a) /* result 0 */
MY_IS_EMPTY(()) /* result 1 */
MY_IS_EMPTY((a)) /* result 0 */
...
Further more, the thing I want to achieve is an contract programming method with function invoking, which parameters are some pointers of structure types or just NULL, some auxiliary macros as below:
#define MY_REF_PRED(d, tuple) BOOST_PP_TUPLE_ELEM(2, 0, tuple)
#define MY_REF_OP(d, tuple) MY_REF_OP_D(MY_REF_OP_SEQ(BOOST_PP_TUPLE_ELEM(2, 1, tuple)))
#define MY_REF_OP_D(seq) \
BOOST_PP_IF(MY_IS_EMPTY(BOOST_PP_SEQ_HEAD(BOOST_PP_SEQ_REVERSE(seq))) \
, (1, BOOST_PP_SEQ_HEAD(seq)) \
, (0, BOOST_PP_SEQ_HEAD(BOOST_PP_SEQ_REVERSE(seq))))
#define MY_REF_OP_SEQ(ref) BOOST_PP_CAT(MY_REF_OP_DEF_, MY_REF_OP_HELPER ref) )
#define MY_REF_OP_HELPER(ref) 00(ref)
#define MY_REF_OP_DEF_00(x) (x)(
#define MY_REF_OP_DEF_MY_REF_OP_HELPER (
#define MY_REF_HELPER(ref) \
BOOST_PP_TUPLE_ELEM(2, 1, BOOST_PP_WHILE(MY_REF_PRED, MY_REF_OP, (1, ref)))
The MY_REF_HELPER macro can be used for deducing whether a parameter is NULL/0 or not:
MY_REF_HELPER(NULL) 0
MY_REF_HELPER(0) 0
MY_REF_HELPER(ptr) ptr
MY_REF_HELPER((struct base_type *)ptr) ptr
MY_REF_HELPER(&x) &x
...
For a idiom we may common use for dealing a series of kinds of data structure or object-oriented kind of programming is defined a base type in library or reusable code, and force the derived type to encapsulate it, so we can check such thing in the base code, with force the client redelare it again except during the definition.
Probable more definitions:
#define MY_REF_DEF_0 )(((struct base_type *)0))( /* sequence trick of boost preprocessor again */
#define MY_REF_SEQ(ref) (BOOST_PP_CAT(MY_REF_DEF_, MY_REF_HELPER(ref)))(ref) /* pasting error again we may meet with ## operator to deal with a & expression */
#define MY_REF(ref) BOOST_PP_SEQ_ELEM(1, MY_REF_SEQ(ref))
The MY_REF add type information to NULL/0 parameters:
MY_REF(0) => ((struct base_type *)0)
MY_REF(NULL) => ((struct base_type *)0)
MY_REF(ptr) => ptr
MY_REF((struct base_type *)ptr) => (struct base_type *)ptr
MY_REF(&x) => error here to for concating &x!!!
If works, the macro invoking can be used to encapsulate a function call with the checking of parameters' type.
#define BUILD_ASSERT_OR_ZERO(cond) (sizeof(char [1 - 2*!(cond)]) - 1)
#define fun(derived) \
__fun(derived + BUILD_ASSERT_OR_ZERO(sizeof((MY_REF(derived))->base_member) == sizeof(struct base_type))) /* or checking with typeof extension of gcc */
So the questions I want to ask are:
1. Is there any existing solution for my problem?
2. Will it be possible to allow such pasting and more meta programming convenience by the standard or by the compiler authors? Though disallowing pasting, the gcc generate same code in some of such situation without ##.