当前位置:  开发笔记 > 编程语言 > 正文

Variadic递归预处理器宏 - 它可能吗?

如何解决《Variadic递归预处理器宏-它可能吗?》经验,为你挑选了5个好方法。

我遇到了一些理论问题.在一段代码中,我维护着一组宏

#define MAX_OF_2(a, b)       (a) > (b) ? (a) : (b)
#define MAX_OF_3(a, b, c)    MAX_OF_2(MAX_OF_2(a, b), c)
#define MAX_OF_4(a, b, c, d) MAX_OF_2(MAX_OF_3(a, b, c), d)
...etc up to MAX_OF_8

我想做的是用这样的东西替换它们:

/* Base case #1, single input */
#define MAX_OF_N(x)      (x)

/* Base case #2, two inputs */
#define MAX_OF_N(x, y)   (x) > (y) ? (x) : (y)

/* Recursive definition, arbitrary number of inputs */
#define MAX_OF_N(x, ...) MAX_OF_N(x, MAX_OF_N(__VA_ARGS__))

...当然,这是无效的预处理器代码.

忽略这个特殊情况应该使用函数而不是预处理器宏来解决,是否可以定义一个可变的MAX_OF_N()宏?

为了清楚起见,最终结果应该是一个宏,它接受任意数量的参数并评估其中最大的参数.我有一种奇怪的感觉,这应该是可能的,但我没有看到如何.



1> DS...:

可以编写一个宏来计算它所调用的参数的数量.(我无法找到一个链接到地方,我第一次看到它.)所以你可以写MAX_OF_N(),将工作,只要你愿意,但你仍然需要所有编号的宏,直到一些限制:

#define MAX_OF_1(a)         (a)         
#define MAX_OF_2(a,b)       max(a, b)

#define MAX_OF_3(a,...)    MAX_OF_2(a,MAX_OF_2(__VA_ARGS__))
#define MAX_OF_4(a,...)    MAX_OF_2(a,MAX_OF_3(__VA_ARGS__))
#define MAX_OF_5(a,...)    MAX_OF_2(a,MAX_OF_4(__VA_ARGS__))
...
#define MAX_OF_64(a,...)   MAX_OF_2(a,MAX_OF_63(__VA_ARGS__))

// NUM_ARGS(...) evaluates to the literal number of the passed-in arguments.
#define _NUM_ARGS2(X,X64,X63,X62,X61,X60,X59,X58,X57,X56,X55,X54,X53,X52,X51,X50,X49,X48,X47,X46,X45,X44,X43,X42,X41,X40,X39,X38,X37,X36,X35,X34,X33,X32,X31,X30,X29,X28,X27,X26,X25,X24,X23,X22,X21,X20,X19,X18,X17,X16,X15,X14,X13,X12,X11,X10,X9,X8,X7,X6,X5,X4,X3,X2,X1,N,...) N
#define NUM_ARGS(...) _NUM_ARGS2(0, __VA_ARGS__ ,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)

#define _MAX_OF_N3(N, ...) MAX_OF_ ## N(__VA_ARGS__)
#define _MAX_OF_N2(N, ...) _MAX_OF_N3(N, __VA_ARGS__)
#define MAX_OF_N(...)      _MAX_OF_N2(NUM_ARGS(__VA_ARGS__), __VA_ARGS__)

现在MAX_OF_N(a,b,c,d,e)将评估max(a, max(b, max(c, max(d, e)))).(我在gcc 4.2.1上测试过.)

请注意,基本case(MAX_OF_2)在扩展中不会多次重复其参数是至关重要的(这就是我放入max此示例的原因).否则,你将每个级别的扩展时间加倍,所以你可以想象64个参数会发生什么:)


这只是迫使一级扩张.如果我放了_MAX_OF_N3(NUM_ARGS(__ VA_ARGS__)等)",跳过中间步骤,它就会扩展到MAX_OF_NUMARGS(__ VA_ARGS __)(等).

2> paxdiablo..:

不,因为预处理器只对文件进行一次"滑动".没有办法让它以递归方式定义宏.

我见过的唯一代码就是这样的代码并不是 variadic,而是使用了用户必须传递的默认值:

x = MAX_OF_8 (a, b, -1, -1, -1, -1, -1, -1)

假设所有值都是非负的.

内联函数至少应该为C++提供相同的功能.正如您所说,最好留给具有类似于的变量参数的函数printf().


它应该是不可能的,但不是因为预处理器是单通道.由于标准称之为"重新扫描和进一步替换",宏替换过程是递归和多遍的.具体定义的机制禁止递归和corecursion.但这仍然可以被打败.对于使用这种语法*的递归*,这是不可能的,因为缺少重载会妨碍编写终止案例.

3> Steve Jessop..:

你可能会考虑这种作弊,因为它不是递归的,它不能在预处理器中完成工作.它使用GCC扩展.它只适用于一种类型.但是,它是一个可变的MAX_OF_N宏:

#include 
#include 

#define MAX_OF_N(...) ({\
        int ra[] = { __VA_ARGS__ }; \
        *std::max_element(&ra[0], &ra[sizeof(ra)/sizeof(int)]); \
    })

int main() {
    int i = 12;
    std::cout << MAX_OF_N(1,3,i,6);
}

哦,是的,并且由于初始化列表中的潜在变量表达式,我不认为相当于此(使用其自己的函数来避免std :: max_element)将在C89中起作用.但我不确定可变参数宏是否也在C89中.

这是我认为围绕"只有一种类型"限制的东西.但是它有点毛茸茸:

#include 
#include 

#define MAX_OF_N(x, ...) ({\
        typeof(x) ra[] = { (x), __VA_ARGS__ }; \
        *std::max_element(&ra[0], &ra[sizeof(ra)/sizeof(ra[0])]); \
    })

int main() {
    int i = 12;
    std::cout << MAX_OF_N(i+1,1,3,6,i);
}


afaik,可变参数宏不是C++的一部分,所以几乎任何组合都变得多毛.:)

4> fortran..:

我认为,即使你可以递归地扩展宏,你的方法在效率方面会有一个小问题......当宏扩展时,如果MAX_OF_[N-1]更大,那么你必须从头开始再次评估它.

这是一个愚蠢而愚蠢的答案,可能没有人会喜欢xD

文件"source.c"

#include "my_macros.h"
...

文件"Makefile"

myprogram: source.c my_macros.h
 gcc source.c -o myprogram

my_macros.h: make_macros.py
 python make_macros.py > my_macros.h

文件"make_macros.py"

def split(l):
    n = len(l)
    return l[:n/2], l[n/2:]

def gen_param_seq(n):
    return [chr(i + ord("A")) for i in range(n)]

def make_max(a, b):
    if len(a) == 1:
        parta = "("+a[0]+")"
    else:
        parta = make_max(*split(a))

    if len(b) == 1:
        partb = "("+b[0]+")"
    else:
        partb = make_max(*split(b))

    return "("+parta +">"+partb+"?"+parta+":"+partb+")"

for i in range(2, 9):
    p = gen_param_seq(i)
    print "#define MAX_"+str(i)+"("+", ".join(p)+") "+make_max(*split(p))

然后你将定义那些漂亮的宏:

#define MAX_2(A, B) ((A)>(B)?(A):(B))
#define MAX_3(A, B, C) ((A)>((B)>(C)?(B):(C))?(A):((B)>(C)?(B):(C)))
#define MAX_4(A, B, C, D) (((A)>(B)?(A):(B))>((C)>(D)?(C):(D))?((A)>(B)?(A):(B)):((C)>(D)?(C):(D)))
#define MAX_5(A, B, C, D, E) (((A)>(B)?(A):(B))>((C)>((D)>(E)?(D):(E))?(C):((D)>(E)?(D):(E)))?((A)>(B)?(A):(B)):((C)>((D)>(E)?(D):(E))?(C):((D)>(E)?(D):(E))))
#define MAX_6(A, B, C, D, E, F) (((A)>((B)>(C)?(B):(C))?(A):((B)>(C)?(B):(C)))>((D)>((E)>(F)?(E):(F))?(D):((E)>(F)?(E):(F)))?((A)>((B)>(C)?(B):(C))?(A):((B)>(C)?(B):(C))):((D)>((E)>(F)?(E):(F))?(D):((E)>(F)?(E):(F))))
#define MAX_7(A, B, C, D, E, F, G) (((A)>((B)>(C)?(B):(C))?(A):((B)>(C)?(B):(C)))>(((D)>(E)?(D):(E))>((F)>(G)?(F):(G))?((D)>(E)?(D):(E)):((F)>(G)?(F):(G)))?((A)>((B)>(C)?(B):(C))?(A):((B)>(C)?(B):(C))):(((D)>(E)?(D):(E))>((F)>(G)?(F):(G))?((D)>(E)?(D):(E)):((F)>(G)?(F):(G))))
#define MAX_8(A, B, C, D, E, F, G, H) ((((A)>(B)?(A):(B))>((C)>(D)?(C):(D))?((A)>(B)?(A):(B)):((C)>(D)?(C):(D)))>(((E)>(F)?(E):(F))>((G)>(H)?(G):(H))?((E)>(F)?(E):(F)):((G)>(H)?(G):(H)))?(((A)>(B)?(A):(B))>((C)>(D)?(C):(D))?((A)>(B)?(A):(B)):((C)>(D)?(C):(D))):(((E)>(F)?(E):(F))>((G)>(H)?(G):(H))?((E)>(F)?(E):(F)):((G)>(H)?(G):(H))))

最好的事情就是......它有效^ _ ^



5> Jason S..:

如果您正在使用C++进入这条道路,请查看模板元编程.它不漂亮,它可能无法解决您的确切问题,但它将处理递归.


+1.变量模板来自C++ 1x,g ++已经实现了它们,但它们将被广泛接受还需要一段时间.遗憾的是,没有它们的模板元编程解决方案仍然需要丑陋的术语嵌套(例如"max_of <3,max_of <4,max_of <5,6> >>"),除非你手动"展开"它们(你可以轻松地做到)使用预处理器宏).模板仍然更好,因为它们可以递归并且不会多次评估参数.
推荐阅读
小妖694_807
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有