Macros 可变递归预处理器宏-可能吗?

Macros 可变递归预处理器宏-可能吗?,macros,c-preprocessor,Macros,C Preprocessor,我遇到了一个理论上的小问题。在我维护的一段代码中,有一组宏,如 #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

我遇到了一个理论上的小问题。在我维护的一段代码中,有一组宏,如

#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()宏


为了清楚起见,最终结果应该是一个宏,它接受任意数量的参数,并计算出其中最大的参数。我有一种奇怪的感觉,这应该是可能的,但我不知道怎么做。

不,因为预处理器只对文件进行一次“扫描”。无法让它递归定义宏

我见过的唯一一个这样做的代码不是可变的,而是使用了用户必须传递的默认值:

x = MAX_OF_8 (a, b, -1, -1, -1, -1, -1, -1)
假设所有值均为非负值


内联函数至少应该为C++提供相同的函数。当你声明时,最好是用一个类似于变量的函数,类似于<代码> Prtff()/< > > < /P> < P>如果你在C++中走这条路,看看。它不漂亮,它可能无法解决你的确切问题,但它会处理递归。

< P>你可以考虑这种作弊,因为它不是递归的,它不做预处理器中的工作。它使用了一个GCC扩展。它只适用于一种类型。然而,它是一个可变的MAX_OF N宏:

#include <iostream>
#include <algorithm>

#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);
}
#包括
#包括
#定义N的最大值(…)({\
int ra[]={{uuu VA_ARGS}\
*std::max_元素(&ra[0],&ra[sizeof(ra)/sizeof(int)])\
})
int main(){
int i=12;

std::cout我认为,即使你可以递归地扩展宏,你的方法在效率方面也会有一个小问题……当宏被扩展时,如果[N-1]
的最大值更大,那么你必须从头开始重新计算它

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

文件“source.c” 文件“Makefile” 文件“make_macros.py” 然后您将定义这些漂亮的宏:

#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))))

最棒的是……它可以工作^ ^ ^

可以编写一个宏,计算它调用的参数数。(我找不到指向我第一次看到它的地方的链接。)因此,您可以编写MAX_of_N(),它可以按您的喜好工作,但您仍然需要所有编号的宏,直到某个限制:

#定义_1(a)(a)的最大值
#定义_2(a,b)的最大_最大(a,b)
#定义3的最大值(a,…)2的最大值(a,2的最大值()
#定义4的最大值(a,…)2的最大值(a,3的最大值()
#定义_5的最大值(a,…)_2的最大值(a,_4的最大值(u VA_ARGS_u))
...
#定义64的最大值(a,…)2的最大值(a,63的最大值()
//NUM_ARGS(…)计算为传入参数的文本数。
#6.X6、X64、X64、X63、X62、X62、X62、X60、X59、X58、X58、X57、X57、X56、X56、X56、X5 5、X5、X5、X5、X5、X5、X6、X6、X6、X6、X6、X6、X6、X6、X6、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X5、X(小标题)N
#定义NUM_ARGS(…)_NUM_ARGS2(0、uu VA_ARGS_uuu、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,35,33,32,30,28,27,26,25,24,22,20,19,18,16,15,14,13,12,11,10,9,4,5,1)
#定义N的最大值(N,…)N的最大值(u VA_ARGS)
#定义N2(N,…)的最大值,N3(N,…)的最大值
#定义N的MAX_(…)\u N2的MAX_(NUM_ARGS(\uu VA_ARGS_uuu),\uu VA_ARGS_uuu)
现在
MAX\u OF N(a,b,c,d,e)
将计算为
MAX(a,MAX(b,MAX(c,MAX(d,e)))
(我已经在gcc 4.2.1上进行了测试。)


请注意,基本情况(
MAX\u OF_2
)在扩展中不重复其参数一次以上是至关重要的(这就是我在本例中放置
MAX
的原因)。否则,每个级别的扩展长度将加倍,因此您可以想象64个参数会发生什么:)

首先,宏不会重复扩展。尽管如此,宏可以通过为每个递归级别创建一个宏,然后推断递归级别来重入。但是,所有这些重复和推断递归离子,由库处理。因此,您可以使用高阶折叠宏来计算最大值:

#define MAX_EACH(s, x, y) BOOST_PP_IF(BOOST_PP_GREATER_EQUAL(x, y), x, y)
#define MAX(...) BOOST_PP_SEQ_FOLD_LEFT(MAX_EACH, 0, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) 

MAX(3, 6, 8) //Outputs 8
MAX(4, 5, 9, 2) //Outputs 9

现在,这将理解0到256之间的文字数。它不能用于C++变量或表达式,因为C预处理器不理解C++。它只是纯文本替换。但是C++提供了一个称为“函数”的特性,它将用于C++表达式,并且可以用它来计算最大值。

template<class T>
T max(T x, T y)
{
    return x > y ? x : y;
}

template<class X, class... T>
auto max(X x, T ... args) -> decltype(max(x, max(args...)))
{
    return max(x, max(args...));
}
模板
T最大值(T x,T y)
{
返回x>y?x:y;
}
模板
自动最大值(X,T…args)->decltype(最大值(X,最大值(args…))
{
返回最大值(x,最大值(args…);
}
现在,上面的代码确实需要C++11编译器。如果您使用C++03,您可以创建函数的多个重载以模拟可变参数。此外,我们可以使用预处理器为我们生成此重复代码(这就是它的用途)。因此,在C++03中,您可以编写以下代码:

template<class T>
T max(T x, T y)
{
    return x > y ? x : y;
}

#define MAX_FUNCTION(z, n, data) \
template<class T> \
T max(T x, BOOST_PP_ENUM_PARAMS(n, T x)) \
{ \
    return max(x, max(BOOST_PP_ENUM_PARAMS(n, x)));\
}

BOOST_PP_REPEAT_FROM_TO(2, 64, MAX_FUNCTION, ~) 
模板
T最大值(T x,T y)
{
返回x>y?x:y;
}
#定义最大值函数(z,n,数据)\
模板\
T max(tx,BOOST_PP_ENUM_PARAMS(n,tx))\
{ \
返回max(x,max(BOOST_PP_ENUM_PARAMS(n,x))\
}
增强\u PP\u重复\u从\u到(2,64,最大\u函数,~)

+1代表“预处理器滥用”标记:)演示了相互递归(投票最多但未被接受的答案)+1。可变模板出现在C++1x中,g++已经实现了它们,但它们被广泛接受还需要一段时间。遗憾的是,没有它们的模板元编程解决方案仍然需要丑陋的术语嵌套(例如“max_of”),除非您手动“展开”它们(您可以使用预处理器宏轻松地展开它们)
#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))))
#define MAX_EACH(s, x, y) BOOST_PP_IF(BOOST_PP_GREATER_EQUAL(x, y), x, y)
#define MAX(...) BOOST_PP_SEQ_FOLD_LEFT(MAX_EACH, 0, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) 

MAX(3, 6, 8) //Outputs 8
MAX(4, 5, 9, 2) //Outputs 9
template<class T>
T max(T x, T y)
{
    return x > y ? x : y;
}

template<class X, class... T>
auto max(X x, T ... args) -> decltype(max(x, max(args...)))
{
    return max(x, max(args...));
}
template<class T>
T max(T x, T y)
{
    return x > y ? x : y;
}

#define MAX_FUNCTION(z, n, data) \
template<class T> \
T max(T x, BOOST_PP_ENUM_PARAMS(n, T x)) \
{ \
    return max(x, max(BOOST_PP_ENUM_PARAMS(n, x)));\
}

BOOST_PP_REPEAT_FROM_TO(2, 64, MAX_FUNCTION, ~)