macro dependent macro
Is it possible to do something like this:
#define F(x) \
#ifdef DOUBLE \
2*x \
#else \
x \
#endif
so that when I use F
, what it expands to depends on whether the macro DOUBLE
is defined? I don't think so, 开发者_JAVA技巧but I'm hopeful. GNU expansions are fine.
Edit In response to some of the answers, I'm really using this to do some code generation, where the code is slightly different depending on where it gets defined. Because of the order in which some files are included and where the relevant macros need to be defined, switching it around that way requires a bit of factoring. I may have to do it, but would be thrilled if I don't have to unpaint myself from this corner!
What's wrong with
#ifdef DOUBLE
#define F(x) (2 * (x))
#else
#define F(x) (x)
#endif
If we can constrain the problem, you can accomplish this. Specifically, if you can guarantee that DOUBLE
is either
- not defined as a macro, or
- is defined as a macro that expands to an empty token sequence (e.g.
#define DOUBLE
),
then you can use an indirect approach with token concatenation:
#define F_IMPL_(x) DOUBLE_IS_DEFINED
#define F_IMPL_DOUBLE(x) DOUBLE_NOT_DEFINED
#define F_1(x, m) F_2(x, m)
#define F_2(x, m) F_IMPL_ ## m ( x )
#define F(x) F_1(x, DOUBLE)
Usage example:
F(t)
#define DOUBLE
F(t)
Result after preprocessing:
DOUBLE_NOT_DEFINED
DOUBLE_IS_DEFINED
This approach will also work if DOUBLE
(if it is defined) is defined as a macro that expands to a single known token, if that token can form part of an identifier (e.g., TRUE
or 1
). To handle this, you just have to rename the F_IMPL_
macro to F_IMPL_{TOKEN}
(e.g., F_IMPL_TRUE
or F_IMPL_1
).
Why not do the nesting the other way around?
#ifdef DOUBLE
#define F(x) (2*(x))
#else
#define F(x) (x)
#endif
No. The closest thing you can do is to put that in a header file, and #include that header file each time the definitions you care about change. This is sometimes called the "X" pattern, because X
is used as a macro that changes definition.
For example, one common usage of that pattern is to autogenerate the string names of enum values:
// File myenum_values.h
// NOTE: _no_ header guards so we can include this file multiple times
X(Apple)
X(Orange)
X(banana)
// File myenum.h
enum Fruit
{
#define X(x) x,
#include "myenum_values.h"
}
const char *FruitNames[] =
{
#undef X
#define X(x) #x,
#include "myenum_values.h"
};
// We now have an array of fruit names without having to define the enum twice
精彩评论