我有concrete_impl.h
(按原样):
#ifdef TUPLE_ITERATOR_WITH_INDEX
#define TUPLE_ITERATOR TUPLE_ITERATOR_NO_INDEX
#define iterate_tuple_fname iterate_tuple_id
#else
#define TUPLE_ITERATOR TUPLE_ITERATOR_INDEX
#define iterate_tuple_fname iterate_tuple
#endif
#undef iterate_tuple_fname_back
#define iterate_tuple_fname_back iterate_tuple_fname##_back
static void iterate_tuple_fname() // ok
{
}
static void iterate_tuple_fname_back() // redefinition error
{
}
concrete.h
(原样):
#ifndef CONCRETE_H
#define CONCRETE_H
#define TUPLE_ITERATOR_WITH_INDEX
#include "concrete_impl.h"
#undef TUPLE_ITERATOR_WITH_INDEX
#include "concrete_impl.h"
#endif // CONCRETE_H
我想得到的是4个功能:
但是" _back"函数我有重新定义错误。为什么呢?
答案 0 :(得分:1)
iterate_tuple_fname##_back
只不过是iterate_tuple_fname_back
。要将iterate_tuple_fname
替换为其宏替换列表,您需要一个辅助宏:
#define CONCAT(a, b) a ## b
#define iterate_tuple_fname_back CONCAT(iterate_tuple_fname, _back)
更新:对不起,经过几年的C#编程,已经忘记了所有关于C的事。
实际上需要 double 运行辅助宏:
#define CONCAT1(a, b) a ## b
#define CONCAT(a, b) CONCAT1(a, b)
#define iterate_tuple_fname_back CONCAT(iterate_tuple_fname, _back)
答案 1 :(得分:0)
显然你误解了##
运算符的工作原理。
如果与##
运算符相邻的预处理标记是当前宏的参数,则递归分析此参数以进一步替换 first ,并将替换结果替换为结果。
如果与##
运算符相邻的预处理标记不是当前宏的参数,则不会进行递归分析和替换该标记。令牌简单地与另一个令牌连接。
稍后,一旦替换了所有参数并连接了所有连接,将再次重新扫描整个结果以进行进一步替换。但是你的例子已经为时已晚。
在您的情况下,您定义了此宏
#define iterate_tuple_fname_back iterate_tuple_fname##_back
由于iterate_tuple_fname
不是此宏的参数,因此iterate_tuple_fname
不会进行早期替换。整个事情立即连接到iterate_tuple_fname_back
,然后才重新扫描。但重新扫描发现没有什么可以替代,所以iterate_tuple_fname_back
是最终的结果。
如果您希望预处理器替换##
运算符的左侧(显然是您的意图),则必须在左侧使用宏参数,如
#define ITF_back(prefix) prefix##_back
然后您可以将此宏用作
ITF_back(iterate_tuple_fname)
现在iterate_tuple_fname
内的重新扫描和递归替换将在与_back
部分串联之前提前发生。即它会像你想要的那样工作。