G. Ko
G. Ko

Reputation: 403

C/C++ macro expansion

I have the following code:

#define UNIT_BASIC_UNIT_DEF2 (name) UNIT_BASIC_ ## name
#define UNIT_UNIT_TYPE_DEF2 (basic_type, name) UNIT_ ## basic_type ## _ ## name
#define UNIT_BASIC_UNIT_CLASS_NAME2(name) CUnit ## name
#define UNIT_UNIT_TYPE_CLASS_NAME2(basic_type, name) CUnit ## basic_type ## _ ## name

#define UNIT_BASIC_UNIT_DEF (name) UNIT_BASIC_UNIT_DEF2(name)
#define UNIT_UNIT_TYPE_DEF (basic_type, name) UNIT_UNIT_TYPE_DEF2 (basic_type, name)
#define UNIT_BASIC_UNIT_CLASS_NAME(name) UNIT_BASIC_UNIT_CLASS_NAME2(name)
#define UNIT_UNIT_TYPE_CLASS_NAME(basic_type, name) UNIT_UNIT_TYPE_CLASS_NAME2(basic_type, name)

#define UNIT_IMPLEMENT_UNIT_TYPE(basic_type, name) \
CUnitAbstract& UNIT_UNIT_TYPE_CLASS_NAME(basic_type, name)::dup(){\
UNIT_UNIT_TYPE_CLASS_NAME(basic_type, name) * n = new UNIT_UNIT_TYPE_CLASS_NAME(basic_type, name)(this->value);\
return *n;\
}\
CUnitAbstract& UNIT_UNIT_TYPE_CLASS_NAME(basic_type, name) ::operator+(CUnitAbstract& value){\
DYNAMIC_ASSERT(dynamic_cast< UNIT_BASIC_UNIT_CLASS_NAME(basic_type) *>(&value) != NULL);\
CUnitAbstract * tmp = &this->dup();\
*tmp = this->value + conversionTable[UNIT_BASIC_UNIT_DEF(basic_type)][UNIT_UNIT_TYPE_DEF(basic_type, name)] * value.getInBasicUnit();return *tmp;\
}

When I'm calling the macro with

UNIT_IMPLEMENT_UNIT_TYPE(DISTANCE, METER)

I get compilation errors:

error: 'basic_type' was not declared in this scope
error: 'name' was not declared in this scope
error: expected ']' before 'UNIT_basic_type_name'
error: expected ';' before 'UNIT_basic_type_name'

meaning that the macro wasn't expanded as I wanted it to in the last line inside the brackets. What did I do wrong?

Upvotes: 3

Views: 3697

Answers (1)

Adam Rosenfield
Adam Rosenfield

Reputation: 400612

#define UNIT_BASIC_UNIT_DEF2 (name) UNIT_BASIC_ ## name
#define UNIT_UNIT_TYPE_DEF2 (basic_type, name) UNIT_ ## basic_type ## _ ## name
...
#define UNIT_BASIC_UNIT_DEF (name) UNIT_BASIC_UNIT_DEF2(name)
#define UNIT_UNIT_TYPE_DEF (basic_type, name) UNIT_UNIT_TYPE_DEF2 (basic_type, name)

Remove the spaces between the macro name and the argument list. These should be:

#define UNIT_BASIC_UNIT_DEF2(name) ...
//                         ^^^
//                     no space here!

When there's a space like this:

#define FOO (params) replacement

that defines an object-like macro, where the symbol gets directly replaced by the replacement list, with no parameter substitution. So an invocation like this:

FOO(bar)

gets expanded to this:

(params) replacement

By removing the space, you get a function-like macro as intended:

#define FOO(params) replacement

and FOO(bar) gets correctly expanded to replacement.

Upvotes: 7

Related Questions