我正在根据参数的数量重载宏,如本问题所述: Overloading Macro on Number of Arguments
展开后,__VA_ARGS__
"推送"宏名称,以便根据参数的数量选择正确的宏名称,然后调用。
我的问题是我想要:
链接问题中的解决方案的问题是第三个参数被用作宏名称,它不起作用。
我希望有一种方法来限制扩展__VA_ARGS__
时扩展的参数数量。类似的东西:
LIMIT_VA_ARGS_TO_2( ... ) ???
LIMIT_VA_ARGS_TO_2( 1 )
提供:1
LIMIT_VA_ARGS_TO_2( 1, 2 )
提供:1, 2
LIMIT_VA_ARGS_TO_2( 1, 2, 3 )
也提供:1, 2
有办法吗?
答案 0 :(得分:3)
我没有看到一种简单的方法来实现这一点,但是有了一些辅助宏,我们就可以做到。
让我们建立一些帮手。首先,如果你知道你有两个或更多的论点,那么很容易抓住第二个:
#define GET_ARG_2(A, B, ...) B
如果您不知道自己至少有两个参数,则可以随时添加一个参数,以确保有第二个参数可以抓取。我们可以把新的东西称为任何我们喜欢的东西,但是如果我们做出一些永远不会成为真正论证的东西,我们可以在以后识别它。在这里,我打电话给它" EXPANDER(〜)",我稍后会解释原因。所以宏总是抓住第二个参数,即使我们只有一个是:
#define FORCE_GET_ARG_2(...) GET_ARG_2( __VA_ARGS__, EXPANDER(~) )
好的 - 下一组辅助宏都是间接的 - 我们在执行被调用的操作时推迟,以确保在执行列出的操作之前首先展开属于参数一部分的任何宏。
#define MERGE(A, B) A ## B
#define INDIRECT_GET_ARG_2(...) GET_ARG_2( __VA_ARGS__)
#define INDIRECT_MERGE(A, B) MERGE(A,B)
现在是时候有点神奇了。我们将计算一个名为COUNT_ARGS_CAP_2的宏中有多少个参数,如果有一个参数,则返回1,或者有两个或多个参数返回2。为此,我们将扩展我们上面使用的魔术EXPANDER(〜)占位符。
我们将在所有输入上使用FORCE_GET_ARG_2。如果存在真正的第二个参数,它将获得它并且它将被视为一个输入参数。然后我们将数字2作为我们的第二个参数(意味着最初至少有两个参数)。但是,如果我们发现EXPANDER(〜)作为我们拉动的参数,我们希望它扩展为占据2个参数位置,第二个参数为1(将2推出)。然后我们抓住我们产生的第二个参数,它就是正确答案。
#define DO_SPECIAL_EXPANDER(x) x, 1
#define COUNT_ARGS_CAP_2(...) \
INDIRECT_GET_ARG_2( INDIRECT_MERGE(DO_SPECIAL_, FORCE_GET_ARG_2( __VA_ARGS__ )), 2 )
如果EXPANDER(〜)以外的任何参数都以DO_SPECIAL_为前缀,那么它将毫无意义并被丢弃。但是如果EXPANDER(〜)以它为前缀,它将变成一个真正的宏并扩展到我们需要的两个参数!
所以,现在我们有办法区分一个参数和两个或更多个参数。让我们用它来构建你最初想要的宏!
#define LIMIT_VA_ARGS_TO_2( ... ) \
INDIRECT_MERGE(LIMIT_VA_ARGS_V, COUNT_ARGS_CAP_2(__VA_ARGS__)) (__VA_ARGS__)
#define LIMIT_VA_ARGS_V1( A, ...) A
#define LIMIT_VA_ARGS_V2( A, B, ...) A, B
我们在这里做的是根据原始参数的数量调用LIMIT_VA_ARGS(V1或V2)的特殊子版本 - 我们确保它始终产生正确的答案。
可能有一种更简单的方法来完成所有这些,但我无法轻易找到一个。 (我很想看看别人是否做过!)