我有concrete_impl.h
(as is):
#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个函数:
- iterate_tuple
- iterate_tuple_id
- iterate_tuple_back
- iterate_tuple_id_back
但是在"_back"函数上,我有重定义错误。为什么?
iterate_tuple_fname##_back
就是iterate_tuple_fname_back
。要用它的宏替换列表替换iterate_tuple_fname
,您需要一个helper宏:
#define CONCAT(a, b) a ## b
#define iterate_tuple_fname_back CONCAT(iterate_tuple_fname, _back)
更新:对不起,在c#编程几年之后,我已经把C忘得一干二净了。
实际上需要double通过helper宏运行:
#define CONCAT1(a, b) a ## b
#define CONCAT(a, b) CONCAT1(a, b)
#define iterate_tuple_fname_back CONCAT(iterate_tuple_fname, _back)
显然你误解了##
操作符的工作方式。
-
如果
##
操作符旁边的预处理令牌是当前宏的参数,则对该参数进行递归分析以进一步替换首先,并将该替换的结果替换到结果中。 -
如果
##
操作符旁边的预处理令牌是而不是当前宏的参数,则不会进行该令牌的递归分析和替换。令牌与另一个令牌简单地连接在一起。
之后,一旦替换了所有参数并连接了所有连接,将再次重新扫描整个结果以进行进一步替换。但是对于你的榜样来说已经太迟了。
在您的例子中,您定义了这个宏#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
部分连接之前。也就是说,它会像你想要的那样工作。