Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overload C/C++ preprocessor macro on structure of its argument

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

like image 340
HighCommander4 Avatar asked Mar 02 '11 19:03

HighCommander4


People also ask

Can macro be overloaded?

Operator overloading only applies to C++ functions and not to macros. Consider that macros are expanded by the preprocessor and and are hence are no longer visible to the following compilation steps.

How do you use macros in arguments?

Function-like macros can take arguments, just like true functions. To define a macro that uses arguments, you insert parameters between the pair of parentheses in the macro definition that make the macro function-like. The parameters must be valid C identifiers, separated by commas and optionally whitespace.

How many arguments macro can have in C?

For portability, you should not have more than 31 parameters for a macro. The parameter list may end with an ellipsis (…). In this case, the identifier __VA_ARGS__ may appear in the replacement list.

What is a macro argument?

Macro Arguments (DEFINE-! ENDDEFINE command) The macro definition can include macro arguments, which can be assigned specific values in the macro call. There are two types of arguments: keyword and positional. Keyword arguments are assigned names in the macro definition; in the macro call, they are identified by name.


2 Answers

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

like image 196
Ise Wisteria Avatar answered Oct 21 '22 13:10

Ise Wisteria


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.

like image 44
KitsuneYMG Avatar answered Oct 21 '22 13:10

KitsuneYMG