Pregunta

I'm writing a library that uses the preprocessor meta-programming Boost.Preprocessor. One macro looks kind of like this:

#define MY_MACRO(my_type) return some_function<my_type>()

Now, the problem is that I need to remove the return if my_type is void. I checked Boost.Preprocessor, but I didn't see anything that could help me. How do I accomplish this? Something like:

#define MY_MACRO(my_type) BOOST_PP_IF(\
      TYPE_EQUALS(my_type,void),return,BOOST_PP_EMPTY()) some_function<my_type>()
¿Fue útil?

Solución

Unfortunately, boost preprocessor doesn't have an easy way to compare two tokens. Of course for your case you may just need to use some simple detection. This should work on C99 preprocessors:

#define CHECK_N(x, n, ...) n
#define CHECK(...) CHECK_N(__VA_ARGS__, 0,)
#define PROBE(x) x, 1,

#define IS_VOID(x) CHECK(BOOST_PP_CAT(IS_VOID_, x))
#define IS_VOID_void PROBE(~)

However, this won't work for parenthesis, for varidiac data(such as types with commas in them), or pointers. So here are the ones that work and don't work:

IS_VOID(int) // 0
IS_VOID(void) // 1
IS_VOID((void)) // Compile error
IS_VOID(std::map<int, int>) // Compile error
IS_VOID(void*) // Returns 1, but should return 0

You could try to work around all these cases or you could use a more general comparison macro(like the one here):

#define IS_PAREN(x) CHECK(IS_PAREN_PROBE x)
#define IS_PAREN_PROBE(...) PROBE(~)

#define IS_COMPARABLE(x) IS_PAREN( CAT(COMPARE_, x) (()) )

#define NOT_EQUAL(x, y) \
IIF(BITAND(IS_COMPARABLE(x))(IS_COMPARABLE(y)) ) \
( \
   PRIMITIVE_COMPARE, \
   1 EAT \
))(x, y)

#define EQUAL(x, y) COMPL(NOT_EQUAL(x, y))

#define COMPARE_void(x) x
#define IS_VOID(x) EQUAL(x, void)

Which could be updated to use boost preprocessor components. This should work for more cases, but still won't work with parenthesis(which may not be a problem).

Finally, this is just a comparison on the textual level, so if the user has typedefed void, it will incorrectly return false:

typedef void my_void;
IS_VOID(my_void) // Returns 0

If you are using the detection technique, you could allow the user to extend it for user-defined voids, like so:

#define IS_VOID(x) CHECK(BOOST_PP_CAT(IS_VOID_, x))
#define IS_VOID_void PROBE(~)
// User-defined void
#define IS_VOID_my_void PROBE(~)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top