6

I would like to write a preprocessor macro that does one thing if it's argument is a parenthesized tuple of tokens, like this:

MY_MACRO((x, y))

and something else if it's just a single token, like this:

MY_MACRO(x)

Is that possible?

How about distinguishing between the number of space-separated tokens, i.e. between MY_MACRO(x) and MY_MACRO(x y)?

Note that I am not trying to overload based on the number of arguments - it's a unary macro in all cases.

EDIT: I am willing to use variadic macros if they help

a3f
  • 8,517
  • 1
  • 41
  • 46
HighCommander4
  • 50,428
  • 24
  • 122
  • 194

2 Answers2

7

As for your first question, the following macros might meet your purpose:

#define CONCAT_( x, y ) x ## y
#define CONCAT( x, y ) CONCAT_( x, y )
#define IS_SINGLE_1(...) 0
#define IGNORE(...)
#define IS_SINGLE_2_0           0 IGNORE(
#define IS_SINGLE_2_IS_SINGLE_1 1 IGNORE(
#define IS_SINGLE( x ) CONCAT( IS_SINGLE_2_, IS_SINGLE_1 x ) )
IS_SINGLE((x, y)) // 0
IS_SINGLE(x)      // 1

Macro IS_SINGLE is expanded to 1 if the argument is single token, otherwise, 0.

Hope this helps

Ise Wisteria
  • 11,259
  • 2
  • 43
  • 26
  • Awesome, thanks! I assume the other one (distinguishing between number of space-separated tokens) is impossible as James said... – HighCommander4 Mar 02 '11 at 20:36
  • 2
    For space-separated it's impossible. For comma-separated, there is a solution for any bounded limit on the number of arguments. – R.. GitHub STOP HELPING ICE Mar 02 '11 at 20:41
  • 1
    @HighCommander4: Thanks! As you mentioned, as for space separated arguments, unless arguments are strictly restricted(for example only `x`, `y` and `z` are allowed), I think it is generally very difficult(impossible?)... If `m4` is allowed, probably it is the way to go :-) – Ise Wisteria Mar 02 '11 at 22:20
  • This is the first time I hear of `m4`... it looks interesting. Thanks for the tip :) – HighCommander4 Mar 03 '11 at 00:26
2

Using boost.preprocessor

#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/seq/for_each.hpp>

#define SEQ (w)(x)(y)(z)

#define MACRO(r, data, elem) BOOST_PP_CAT(elem, data)

BOOST_PP_SEQ_FOR_EACH(MACRO, _, SEQ) // expands to w_ x_ y_ z_

It's not exactly the same as even a single argument case requires parenthesis. But It does allow a variable number of parenthesized arguments.

Also a possibility: Use the BOOST_PP_IF, BOOST_PP_EQUAL, and BOOST_PP_TUPLE_ELEM to do something like:

MACRO(1, a)
MACRO(2, (a,b) )
MACRO(3, (a,b,c) )

or so.

KitsuneYMG
  • 12,753
  • 4
  • 37
  • 58