我可以编写一个单参数宏,它采用由空格分隔的单词/标记序列,并生成相同的序列,但每个单词/标记之间有下划线?
当然,这是不可能的。预处理器中没有字符串操作实用程序。
哦,我在开玩笑呢。首先,你必须建立一个包含所有可能的单词组合的字典。为此,我们将有一本包含几个单词的小词典:
#define WORD_world world,
#define WORD_new new,
// etc.
你可能会得到这个模式。然后让我们实现将执行以下操作的宏:
brave new world // our starting argument
WORD_##brave new world // add WORD_ to all arguments and join arguments with spaces
WORD_brave new world
brave, new world // expand WORD_brave macro
WORD_brave WORD_new world // add WORD_ to all arguments and join arguments with spaces
brave, new, world // expand WORD_* macros
WORD_brave WORD_new WORD_world // add WORD_ to all arguments and join arguments with spaces
brave, new, world, // expand WORD_* macros
/* --- repeat above steps up to maximum words you need to handle --- */
brave_new_world // join arguments with `_` ignoring last empty one
以下代码:
// our dictionary
#define WORD_world world,
#define WORD_new new,
#define WORD_brave brave,
#define WORD_hello hello,
#define WORD_Hello Hello,
// 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 MAGIC_MACRO(a) JOIN(WORDS(WORDS(WORDS(WORDS(WORDS(a))))))
MAGIC_MACRO(brave new world)
MAGIC_MACRO(Hello world)
生产:
brave_new_world
Hello_world