Using commas inside a macro without parenthesis: H

2019-01-19 00:23发布

问题:

Consider a simple macro:

#define ECHO(x) x

ECHO(foo(1, 2))

This produces the exact output we expect:

foo(1, 2)

The above example works because the parenthesis adjacent to the function call are recognized by the preprocessor.

Now consider what happens if I use a template instead of a function call:

ECHO(template<int, bool>)

This causes an error because the preprocessor interprets the template<int and the bool> as two separate arguments to the macro. The preprocessor doesn't recognize <> for scope!

Is there anyway to use a template like this in a macro?

回答1:

#define COMMA ,
ECHO(template<int COMMA bool>)

A little painful, but it works.

FWIW, if the syntax for the argument allows ()s, you don't need the substitution, e.g.,

ECHO((a, b))

will work for a single argument macro but that doesn't work in all cases (including yours).



回答2:

A variadic macro may help:

#define ECHO(x...) x

ECHO(foo(1, 2))
ECHO(template<int, bool>)


回答3:

if you allow usage of Cog in your project, your code becomes more readable:

/*[[[cog
# definitions ----
import cog

def AddDeclaration( templateArg , restOfDeclaration ):
    cog.outl(' %s struct %s; ' % (templateArg , restOfDeclaration))

# generation ---
types = ['bool' , 'std::string']
names = ['Foo' , 'Bar']
for index in range(len(names)):
    AddDeclaration( 'template<int, %s>' % types[index] , names[index])
]]]*/
//[[[end]]]

After you run cog over this file, you'll get:

/*[[[cog
# definitions ----
import cog

def AddDeclaration( templateArg , restOfDeclaration ):
    cog.outl(' %s struct %s; ' % (templateArg , restOfDeclaration))

# generation ---
types = ['bool' , 'std::string']
names = ['Foo' , 'Bar']
for index in range(len(names)):
    AddDeclaration( 'template<int, %s>' % types[index] , names[index])
]]]*/
template<int, bool> struct Foo; <---------------- generated by Cog!!
template<int, std::string> struct Bar;
//[[[end]]]

You can even move your definitions in separate .py files and the cog section will look like:


declarations.py

import cog

def AddDeclaration( templateArg , restOfDeclaration ):
    cog.outl(' %s struct %s; ' % (templateArg , restOfDeclaration))

my.h

/*[[[cog
# definitions ----
import declarations
# generation ---
types = ['bool' , 'std::string']
names = ['Foo' , 'Bar']
for index in range(len(names)):
    AddDeclaration( 'template<int, %s>' % types[index] , names[index])
]]]*/
template<int, bool> struct Foo;
template<int, std::string> struct Bar;
//[[[end]]]

the main advantage of using cog is that you gain complete control of your code generation, completely avoid unreadable messes using boost preprocessor or stuff like that.

the main disadvantage is that you add a new tool dependency to your project, also since you need to wrap its usage in comments with the cog section markers, it might actually be worse than writing the code manually for small usages. It really pays off when you need to declare big enums or lot of unavoidable boilerplate code



标签: c++ macros