Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to map #define's replacement list containing space(s) to integers (IDs)?

A #define's replacement list containing no spaces can be mapped to integers (IDs):

#define ID_double       1
#define ID_float        2
#define ID_long_double  3
#define ID_(x)          ID_##x
#define ID(x)           ID_(x)

#define T               double
T v;
int x = ID(T);          /* 1 */

Now consider:

#define T               long double

The code above won't compile:

<source>:3:25: error: 'ID_long' undeclared here (not in a function)

Question: is there a way to support spaces?

For example (somehow):

#define REPLACE_SPACES_TO_UNDERSCORES(x)     ??

#define ID(x)           ID_(REPLACE_SPACES_TO_UNDERSCORES(x))

#define T               long double
T v;
int x = ID(T);          /* 3 */
like image 234
pmor Avatar asked Feb 03 '26 11:02

pmor


1 Answers

The same idea I had in Replace spaces with underscores in a macro? can also be used here, and the dictionary will be much more realistical in size. In the following code on the end, ID(T) is replaced by 3.

// dictionary
#define WORD_long     long,
#define WORD_double   double,

// ---------------------------------------------

// the classics
#define COMMA(...)  ,
#define FIRST(a, ...)  a

// apply function f for each argument recursively with tail
#define FOREACHTAIL_1(f,a)      f(a,)
#define FOREACHTAIL_2(f,a,...)  f(a,FOREACHTAIL_1(f,__VA_ARGS__)) 
#define FOREACHTAIL_3(f,a,...)  f(a,FOREACHTAIL_2(f,__VA_ARGS__)) 
#define FOREACHTAIL_4(f,a,...)  f(a,FOREACHTAIL_3(f,__VA_ARGS__)) 
#define FOREACHTAIL_N(_4,_3,_2,_1,N,...)  \
        FOREACHTAIL_##N
#define FOREACHTAIL(f,...) \
        FOREACHTAIL_N(__VA_ARGS__,4,3,2,1)(f,__VA_ARGS__)

// if there are two arguments, expand to true. Otherwise false.
#define IFTWO_N(_0,_1,N,...)     N
#define IFTWO(true, false, ...)  IFTWO_N(__VA_ARGS__, true, false)

// If empty, expand to true, otherwise false.
// https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/
#define IFEMPTY(true, false, ...)  IFTWO(true, false, COMMA __VA_ARGS__ ())

// Join arguments with `_`.
#define JOIN_U(a, b)      a##_##b
#define JOIN_TWO_IN(a,b)  IFEMPTY(FIRST, JOIN_U, b)(a, b)
#define JOIN_TWO(a,b)     JOIN_TWO_IN(a,b)
#define JOIN(...)         FOREACHTAIL(JOIN_TWO, __VA_ARGS__)

// Append WORD_ to each argument and join arguments with spaces.
#define WORD_             /* the last one expands to empty */
#define WORDS_TWO(a, b)   WORD_##a b
#define WORDS(...)        FOREACHTAIL(WORDS_TWO, __VA_ARGS__)

#define REPLACE_SPACES_TO_UNDERSCORES(a)  JOIN(WORDS(WORDS(WORDS(WORDS(WORDS(a))))))

// --------------------------------------------

#define ID_double       1
#define ID_float        2
#define ID_long_double  3
#define ID_IN2(x)       ID_##x
#define ID_IN(x)        ID_IN2(x)
#define ID(x)           ID_IN(REPLACE_SPACES_TO_UNDERSCORES(x))

int main() {
    #define T               long double
    T v;
    int x = ID(T);          /* 3 */
}
like image 80
KamilCuk Avatar answered Feb 06 '26 01:02

KamilCuk



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!