#define CAT( A, B ) A ## B
#define SELECT( NAME, NUM ) CAT( NAME ## _, NUM )
#define GET_COUNT( _1, _2, _3, _4, _5, _6 /* ad nauseam */, COUNT, ... ) COUNT
#define VA_SIZE( ... ) GET_COUNT( __VA_ARGS__, 6, 5, 4, 3, 2, 1 )
#define VA_SELECT( NAME, ... ) SELECT( NAME, VA_SIZE(__VA_ARGS__) )(__VA_ARGS__)
用法:
#define MY_OVERLOADED( ... ) VA_SELECT( MY_OVERLOADED, __VA_ARGS__ )
#define MY_OVERLOADED_1( X ) foo< X >
#define MY_OVERLOADED_2( X, Y ) bar< X >( Y )
#define MY_OVERLOADED_3( X, Y, Z ) bang_ ## X< Y >.Z()
// This is how user may define own set of variadic macros
#define MY_MACRO(...) VA_MACRO(MY_MACRO, __VA_ARGS__)
#define MY_MACRO1(_1) "One"
#define MY_MACRO2(_1, _2) "Two"
#define MY_MACRO3(_1, _2, _3) "Three"
用法
// While using those, user needs to use only the main macro
int main ()
{
auto one = MY_MACRO(1);
auto two = MY_MACRO(1, 2);
auto three = MY_MACRO(1, 2, 3);
}
#define MY_OVERLOADED(...) VA_MACRO(MY_OVERLOADED, void, void, __VA_ARGS__)
#define MY_OVERLOADED0(s, t) MacroTest()
#define MY_OVERLOADED1(s, t, a) MacroTest( a)
#define MY_OVERLOADED2(s, t, a, b) MacroTest(a, b)
#define MY_OVERLOADED3(s, t, a, b, c) MacroTest(a, b, c)
5条答案
按热度按时间brccelvz1#
(Edit:请参阅结尾部分了解现成的解决方案。)
要得到一个重载宏,首先我们需要一个在几个实现之间进行选择的宏。这部分不使用可变参数宏。然后,一个通用地计算其参数的可变参数宏产生一个选择器。将参数计数插入到一个调度器中产生一个重载宏。
MACRO()
。要在实现之间进行选择,请将宏链接运算符与一系列类似函数的宏一起使用。
因为
##
运算符禁止其参数的宏展开,所以最好将其 Package 在另一个宏中。要计算参数,可以使用
__VA_ARGS__
来移位参数,如下所示(这是比较聪明的部分):库代码:
用法:
vof42yt12#
以下是对Potatoswatter's answer的改进,它可以区分零和一个参数。
简而言之,当
__VA_ARGS__
为空时,VA_SIZE
宏中的EXPAND __VA_ARGS__ ()
变为EXPAND ()
,并被6个逗号替换。因此,VA_SIZE...
变为COMPOSE( GET_COUNT, (,,,,,, , 0, 6, 5, 4, 3, 2, 1) )
,而COMPOSE( GET_COUNT, (,,,,,, , 0, 6, 5, 4, 3, 2, 1) )
变为GET_COUNT (,,,,,, , 0, 6, 5, 4, 3, 2, 1)
并返回0。另一方面,当
__VA_ARGS__
为例如int, 5
时,EXPAND __VA_ARGS__ ()
变为EXPAND int, 5 ()
,因此,VA_SIZE...
变为COMPOSE( GET_COUNT, (EXPAND int, 5 (), 0, 6, 5, 4, 3, 2, 1) )
,COMPOSE( GET_COUNT, (EXPAND int, 5 (), 0, 6, 5, 4, 3, 2, 1) )
变为GET_COUNT (EXPAND int, 5 (), 0, 6, 5, 4, 3, 2, 1)
并返回2,如Potatoswatter的答案中所述。我从Jason Dang's answer那里得到了
EXPAND
的想法。库代码:
用法:
lc8prwob3#
我想把这个作为对Potatoswatter帖子的评论,但是它太长了,需要一个代码清单。
下面是一些perl代码,用于生成一组宏,这些宏将被重载。
下面是脚本的输出:
这些是用于生成
FOR_EACH
的宏重载组(的规则结构部分)(a.k.a.FE
)宏,可以选择性地使用任意数量的常量参数来调度WHAT
宏(A1
,A2
...)除了列表中任意数量的自变量之外,以及适当排序的索引(不使用诸如SELECT
之类的重载的简单实现将产生反转的索引)。例如,剩余部分(第二个块的非常规"基本情况"部分)如下所示:
这种做法的效用也许会受到质疑(我建造它是因为我看到了它的用途......),这也没有直接回答OP的问题(事实上,它的作用正好相反--foreach构造对所有变量参数做同样的事情......),但我只是觉得这个技术很有趣(以及在某些方面完全可怕)并且允许使用预处理器的相当多的表达能力,并且将有可能以这种方式生成非常有效的机器代码。我认为这也是一个尖锐的例子,说明了为什么我个人认为C预处理器仍然有改进的空间。
我的意思是C预处理器是一个绝对令人厌恶的东西,我们可能应该废弃它,从头开始:)
klsxnrf14#
虽然已经有答案了,但我准备了一个很短的版本,希望能有所帮助。
实施
定制
用法
qxsslcnc5#
我扩展了Potatowatter的解决方案,以避免在使用gcc的编译器开关
-pedantic
时出现iso c99 requires rest arguments to be used
问题。零参数也是可能的
图书馆
定制
注意:在这个例子中
MacroTest
是你重载的C++函数。但是你可以在这里放置一个函数。用法
完整示例
使用https://www.onlinegdb.com/online_c++_compiler和https://www.jdoodle.com/online-compiler-c++/进行测试