我需要从宏参数列表中删除最后一个尾随逗号(因为它们最终将被扩展为模板参数,其中不允许尾随逗号)。
所以我需要一个宏remove_trailing_comma()
,它叫做remove_trailing_comma(arg1, arg2, arg3, )
,扩展到arg1, arg2, arg3
。
我尝试过使用varargs和__VA_OPT__
的不同组合,但我似乎无法做到这一点。
例如:
#define discard_trailing_comma(arg, ...) \
arg __VA_OPT__(,) discard_trailing_comma(__VA_ARGS__)
discard_trailing_comma(1, 2, 3, )
由于扩展到1 , discard_trailing_comma(2, 3,)
,我不知道为什么(宏不是递归展开的?)
这在C++20中是可能的吗?
发布于 2022-06-07 18:49:48
您可能应该使用@eljay的答案,但是如果您需要支持更多的参数,这里有一个在22行中支持~2000参数,并且增加更多的行以指数方式增长的参数。
#define E4(...) E3(E3(E3(E3(E3(E3(E3(E3(E3(E3(__VA_ARGS__))))))))))
#define E3(...) E2(E2(E2(E2(E2(E2(E2(E2(E2(E2(__VA_ARGS__))))))))))
#define E2(...) E1(E1(E1(E1(E1(E1(E1(E1(E1(E1(__VA_ARGS__))))))))))
#define E1(...) __VA_ARGS__
#define EMPTY()
#define TUPLE_AT_2(x,y,...) y
#define TUPLE_TAIL(x,...) __VA_ARGS__
#define CHECK(...) TUPLE_AT_2(__VA_ARGS__,0,)
#define EQ_END_END ,1
#define SCAN(...) __VA_ARGS__
#define CAT(a,b) CAT_(a,b)
#define CAT_(a,b) a##b
#define LOOP_() LOOP
#define LOOP(x,y,...) CAT(LOOP, CHECK(EQ_END_##y))(x,y,__VA_ARGS__)
#define LOOP1(x,...) (TUPLE_TAIL x)
#define LOOP0(x,y,...) LOOP_ EMPTY() ()((SCAN x, y),__VA_ARGS__)
#define DTC(...) E4(LOOP((), __VA_ARGS__ END))
DTC (1, 2, 3, 4, 5, 6, 7, 8, 9,) // expands to: (1, 2, 3, 4, 5, 6, 7, 8, 9)
让我解释一下。
首先,当LOOP
在E4()
中被调用时,它可以递归地调用自己,这是在LOOP0中完成的。这方面最简单的例子是#define LOOP(...) __VA_ARGS__ LOOP_ EMPTY() ()(__VA_ARGS__)
,它重复参数,直到递归限制,这是受E4
嵌套约束的。Understanding DEFER and OBSTRUCT macros已经很好地解释了这种行为,所以我将跳过这部分解释。
现在的想法如下:我们循环每个参数,直到我们到达最后一个参数,在其中插入了一个END
标记。在这样做的同时,我们构建了一个新的参数列表,但是当我们到达END
标记时,这也会停止。
如果参数CAT(LOOP, CHECK(EQ_END_##y))
持有结束标记END
,则将分支到LOOP1
,否则将分支到LOOP0
。
LOOP1
使用x
将一个新的参数添加到我们的参数列表中。由于我们从一个空参数列表开始,我们将以一个前导空参数结束,我们可以在LOOP0
上删除该参数。
PS:这个概念可以扩展到E5
,E6
,.,尽管使用这个概念有更大的开销,因为一旦递归结束,预处理器仍然需要重新扫描结果直到递归限制。如果您想纠正这种情况,您可以使用order-pp中的延续机器,它实际上可以终止,但是它大约是150 loc。
编辑,我刚刚重新讨论了这一点,并意识到使用x
构建元组是非常低效的,下面是一个不这样做的版本:
#define E4(...) E3(E3(E3(E3(E3(E3(E3(E3(E3(E3(__VA_ARGS__))))))))))
#define E3(...) E2(E2(E2(E2(E2(E2(E2(E2(E2(E2(__VA_ARGS__))))))))))
#define E2(...) E1(E1(E1(E1(E1(E1(E1(E1(E1(E1(__VA_ARGS__))))))))))
#define E1(...) __VA_ARGS__
#define EMPTY()
#define FX(f,x) f(x)
#define TUPLE_AT_2(x,y,...) y
#define TUPLE_TAIL(x,...) __VA_ARGS__
#define CHECK(...) TUPLE_AT_2(__VA_ARGS__,0,)
#define EQ_END_END ,1
#define CAT(a,b) CAT_(a,b)
#define CAT_(a,b) a##b
#define LOOP_() LOOP
#define LOOP(x,...) CAT(LOOP, CHECK(EQ_END_##x))(x,__VA_ARGS__)
#define LOOP1(x,...)
#define LOOP0(x,...) LOOP_ EMPTY() ()(__VA_ARGS__),x
#define DTC(...) (FX(TUPLE_TAIL,E4(LOOP(__VA_ARGS__ END))))
DTC (1, 2, 3, 4, 5, 6, 7, 8, 9,) // expands to: (1, 2, 3, 4, 5, 6, 7, 8, 9)
发布于 2022-06-07 15:59:07
假设您有一定数量的参数,您可以让一个类似于委托函数的宏作为一个助手来选择适当的实现宏。
#define GET_DTC(_1,_2,_3,_4,NAME,...) NAME
#define DTC4(_1,_2,_3,_4) _1,_2,_3
#define DTC3(_1,_2,_3) _1,_2
#define DTC2(_1,_2) _1
#define DTC1(_1)
#define discard_trailing_comma(...) \
GET_DTC(__VA_ARGS__, DTC4, DTC3, DTC2, DTC1)(__VA_ARGS__)
int arr[] = {
discard_trailing_comma(1, 2, 3, )
};
https://stackoverflow.com/questions/72533711
复制相似问题