tmlen
tmlen

Reputation: 9092

Evaluate macro depending if another macro is defined

The following preprocessor-based identifier-to-string lookup table:

#include <iostream>

// included generated file
#define KEY_a valueA
#define KEY_b valueB
///////

#define LOOKUP_(_key_) KEY_ ## _key_
#define QUOTE_(_str_) #_str_
#define EXPAND_AND_QUOTE_(_str_) QUOTE_(_str_)

#define LOOKUP(_key_) EXPAND_AND_QUOTE_(LOOKUP_(_key_))

int main() {
    std::cout << LOOKUP(a) << std::endl;
    std::cout << LOOKUP(b) << std::endl;
    std::cout << LOOKUP(c) << std::endl;
}

Output:

valueA
valueB
KEY_c

The first #defines come from an #included header generated by an external script before the compilation.

The LOOKUP macro correctly handles existing key in the table, and substitutes the given value as string literal.

But for non-existing keys, it substitutes the key as string literal.

Is there a way to instead make it substitute a given constant for non-existing keys, without causing a compile-time error, and all within the preprocessing stage?

So for example, the LOOKUP(c) and LOOKUP(whatever) should all be substituted to "undefined", without c or whatever occuring in the included generated file.

The names of the keys should not be outputted to the compiled binary, so ideally they should never be seen by the compiler.

Upvotes: 3

Views: 474

Answers (1)

rici
rici

Reputation: 241671

Here's a simple, if hacky, solution. By making the definition of KEY_x a list of two elements (the first of which will be ignored), it permits adding a default value:

#include <iostream>

// included generated file
#define KEY_a _,valueA
#define KEY_b _,valueB
///////

#define LOOKUP_(key) KEY_ ## key
#define QUOTE_(_,str,...) #str
#define EXPAND_AND_QUOTE_(...) QUOTE_(__VA_ARGS__)

#define LOOKUP(key) EXPAND_AND_QUOTE_(LOOKUP_(key),undefined)

int main() {
    std::cout << LOOKUP(a) << std::endl;
    std::cout << LOOKUP(b) << std::endl;
    std::cout << LOOKUP(c) << std::endl;
}

Test on coliru

Upvotes: 5

Related Questions