简体   繁体   中英

C++ Preprocessor macro selection by argument

I'm trying to define a preprocessor macro that in turn selects the right macro depending on the value of an argument.

#define BIT_8(n) n, "is lower or equal than 8"
#define BIT_N(n) n, "is greater than 8"
#define BIT(n) ?????

int main() {
    printf("%d %s", BIT(9));
    return 0;
}

BIT(n) should expand to:

BIT_8(n) if n≤8
BIT_N(n) if n>8

Any way to achieve this?

Unless you want very clumsy code, you can't do that. The preprocessor has no idea about the value of the argument passed in. It's just doing string replacement and that's all.

That being said, they are crazy guys implementing BIT_x for all x in [0 to 63]. This is very ugly and would fail is used with an argument set at 64.

A clean solution is to use a function instead:

const char * bit_msg(unsigned int b)
{
    if (b > 8) return "is greater than 8";
    const char * bits[] = {
"is 0 and lower than 8",
"is 1 and lower than 8",
"is 2 and lower than 8",
"is 3 and lower than 8",
"is 4 and lower than 8",
"is 5 and lower than 8",
"is 6 and lower than 8",
"is 7 and lower than 8",
"is 8",
}; 
return bits[b];
}

#define BIT(X) X, bit_msg(X)
[...]
printf("%d %s", BIT(9));

Because you've tagged the question with C++ and to follow @Romen you could achieve similar result using constexpr that, if possible, will be computed by the compiler at compile time, resulting in code that's as efficient as a macro.

In the example above, you'll just need to replace the signature with constexpr const char * bit_msg(unsigned int b) and the compiler might even skip the function and write (the equivalent of) printf("%d %s", 9, "is greater than 8") .

you could do this

#include <stdio.h>

#define BIT_8(n) printf("%d is lower than or equal to 8 \n" , n)
#define BIT_N(n) printf("%d is greater than 8 \n" , n)
#define BIT(n) ((n <= 8) ? (BIT_8(n)) : (BIT_N(n)))

int main() {
    BIT(7);
    BIT(8);
    BIT(9);
    return 0;
}

The challenge is that the pre-processor doesn't know math. You can solve this problem by implementing the math you need, but it gets UGLY. For example, here's working pre-processor code for what you want to do:

#include <stdio.h>

#define BIT_8(n) n, "is lower or equal than 8"
#define BIT_N(n) n, "is greater than 8"

// Identify values less than 8; make the second argument 8
#define LT_8_0 ~,8
#define LT_8_1 ~,8
#define LT_8_2 ~,8
#define LT_8_3 ~,8
#define LT_8_4 ~,8
#define LT_8_5 ~,8
#define LT_8_6 ~,8
#define LT_8_7 ~,8
#define LT_8_8 ~,8

// Helper macros.  Delays let arguments be processed before the macros is run.
#define MERGE(A, B) A ## B
#define MERGE_DELAY(A, B) MERGE(A,B)
#define ARG2(A,B,...) B
#define ARG2_DELAY(A,B,...) ARG2(A,B,__VA_ARGS__)

// Return 8 or N depending if n <= 8...
#define LT_8(n) ARG2_DELAY( MERGE(LT_8_, n), N,~ )

#define BIT(n) MERGE_DELAY(BIT_, LT_8(n))(n)

int main() {
  printf("%d %s\n", BIT(9));
  return 0;
}

Note that the LT_8 macro works by taking the second of a series of arguments. We default that second argument to N, but if we recognize the input number to be 8 or less, we insert a new second argument of 8.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM