我想实现一个新的max / min宏,它可以使用两个以上的参数,例如:
#define max( ... ) ...
然后,我可以像这样使用它:
max( p0, p1, p2, p3 )
max( 2, 4, 100 )
max( 1,2,3,4,5,6,7 ) -> 7
如果这个宏可以帮助我们实现那个宏吗?
#define PP_EXPAND(X) X
#define PP_ARG_COUNT(...) PP_EXPAND(PP_ARG_POPER(__VA_ARGS__, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
#define PP_ARG_POPER(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, N, ...) N
#define PP_ARG_AT(Index, ...) PP_ARG_AT_##Index(__VA_ARGS__)
#define PP_ARG_AT_0(...) PP_EXPAND(PP_ARG_POPER(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, __VA_ARGS__))
#define PP_ARG_AT_1(...) PP_EXPAND(PP_ARG_POPER(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, __VA_ARGS__))
#define PP_ARG_AT_2(...) PP_EXPAND(PP_ARG_POPER(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, __VA_ARGS__))
#define PP_ARG_AT_3(...) PP_EXPAND(PP_ARG_POPER(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, __VA_ARGS__))
#define PP_ARG_AT_4(...) PP_EXPAND(PP_ARG_POPER(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, __VA_ARGS__))
#define PP_ARG_AT_5(...) PP_EXPAND(PP_ARG_POPER(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, __VA_ARGS__))
#define PP_ARG_AT_6(...) PP_EXPAND(PP_ARG_POPER(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, __VA_ARGS__))
#define PP_ARG_AT_7(...) PP_EXPAND(PP_ARG_POPER(_1, _2, _3, _4, _5, _6, _7, _8, _9, __VA_ARGS__))
#define PP_ARG_AT_8(...) PP_EXPAND(PP_ARG_POPER(_1, _2, _3, _4, _5, _6, _7, _8, __VA_ARGS__))
#define PP_ARG_AT_9(...) PP_EXPAND(PP_ARG_POPER(_1, _2, _3, _4, _5, _6, _7, __VA_ARGS__))
#define PP_ARG_AT_10(...) PP_EXPAND(PP_ARG_POPER(_1, _2, _3, _4, _5, _6, __VA_ARGS__))
#define PP_ARG_AT_11(...) PP_EXPAND(PP_ARG_POPER(_1, _2, _3, _4, _5, __VA_ARGS__))
#define PP_ARG_AT_12(...) PP_EXPAND(PP_ARG_POPER(_1, _2, _3, _4, __VA_ARGS__))
#define PP_ARG_AT_13(...) PP_EXPAND(PP_ARG_POPER(_1, _2, _3, __VA_ARGS__))
#define PP_ARG_AT_14(...) PP_EXPAND(PP_ARG_POPER(_1, _2, __VA_ARGS__))
#define PP_ARG_AT_15(...) PP_EXPAND(PP_ARG_POPER(_1, __VA_ARGS__))
#define PP_ARG_AT_16(...) PP_EXPAND(PP_ARG_POPER( __VA_ARGS__))
答案 0 :(得分:4)
在C ++ 11中,std::max
与initializer_list
一起使用,因此您可以使用
std::max({40, 31, 42, 13, 4, 25, 16, 27});
如果你真的想要MAX(p1, p2, p3)
语法,你可以这样做:
#define MAX(...) std::max({__VA_ARGS__})
答案 1 :(得分:2)
有C ++ STL算法可以做同样的事情:
开始使用这些而不是编写宏来实现这一点:
int arr[] = {1,2,3,4,5};
int* min = std::min_element(arr, arr+5);
int* max = std::max_element(arr,arr+5);
std::cout<<"min:"<<*min<<"max:"<<*max<<std::endl;
答案 2 :(得分:2)
使用Boost.Preprocessor,您可以像这样实现:
#define MAX_FOLD(s, state, elem) BOOST_PP_MAX(state, elem)
#define MAX(...) BOOST_PP_SEQ_FOLD_LEFT(MAX_FOLD, 0, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
由于预处理器在扩展期间不直接支持比较,因此从头开始实现所有这些工作需要做很多工作。使用技术here,您可以实现计数器和while循环结构。有了它,您可以实现减法,这将允许您实现小于(或大于)MAX
所需的。然后使用另一个while
,您可以对varidiac参数进行折叠。
最后,在预处理器中执行所有这些操作存在一些限制。预处理器并不完全完整。因此在boost示例中,您将被限制为0到256之间的值(这完全是一个提升限制,如果您自己动手,则可以提高该限制)。根据您想要实现的目标,最好为max:
编写varidiac函数template<class T, class U>
T max(T x, T y)
{
return x > y ? x : y;
}
template<class... Ts>
T max(T x, Ts... xs)
{
return max(x, max(xs...));
}
答案 3 :(得分:1)
您的问题包含答案的一半-您可以使用min
宏中显示的技术,使用变量参数number建立max
/ PP_ARG_COUNT
宏(与原始代码一样,编号的参数将有限制,但您可以选择)。
以下是示例代码(最多4个参数):
#include <stdio.h>
#define __START(op, A, B, C, D, N, ...) __ARGS_##N(op, A, B, C, D)
#define __ARGS_1(op, A, B, C, D) A
#define __ARGS_2(op, A, B, C, D) __##op(A, B)
#define __ARGS_3(op, A, B, C, D) __##op(A, __##op(B, C))
#define __ARGS_4(op, A, B, C, D) __##op(__##op(A, B), __##op(C, D))
#define __MIN(A, B) ((A) < (B) ? (A) : (B))
#define __MAX(A, B) ((A) > (B) ? (A) : (B))
#define min(...) __START(MIN, __VA_ARGS__, 4, 3, 2, 1)
#define max(...) __START(MAX, __VA_ARGS__, 4, 3, 2, 1)
int main(void)
{
printf("min(1) -> %d\n\n", min(1));
printf("min(1.5, 2) -> %lf\n", min(1.5,2));
printf("min(3, 2, 1.5) -> %lf\n", min(3,2,1.5));
printf("min(1, 2, 3, 4) -> %d\n", min(1,2,3,4));
printf("min(2, 3, 4, 1) -> %d\n\n", min(2,3,4,1));
printf("max(2.5, 2.0) -> %lf\n", max(2.5, 2.0));
printf("max(3, 2, 3.5) -> %lf\n", max(3, 2, 3.5));
printf("max(1, 2, 3, 4) -> %d\n", max(1, 2, 3, 4));
printf("max(2, 3, 4, 1) -> %d\n", max(2, 3, 4, 1));
return 0;
}
如果编译并运行程序,您将获得以下输出:
min(1) -> 1
min(1.5, 2) -> 1.500000
min(3, 2, 1.5) -> 1.500000
min(1, 2, 3, 4) -> 1
min(2, 3, 4, 1) -> 1
max(2.5, 2.0) -> 2.500000
max(3, 2, 3.5) -> 3.500000
max(1, 2, 3, 4) -> 4
max(2, 3, 4, 1) -> 4
工作原理。 __START
宏采用以下参数:
op
-宏名称(前面没有双下划线),仅需两个参数即可进行必要的操作A
,B
,C
,D
-这些自变量将接收min
/ max
的自变量,并可能接收一些虚拟变量如果min
/ max
参数的数量小于最大值(在此示例代码中为4),则返回一个。N
-min
/ max
自变量的数量。 ...
-其他一些虚拟参数。 __START
将扩展为__ARGS_1
.. __ARGS_4
之一,具体取决于参数编号。通过添加调用4, 3, 2, 1
宏的__START
个参数来获得参数编号:
#define min(...) __START(MIN, __VA_ARGS__, 4, 3, 2, 1)
因此,如果您调用实例min(1.5, 2.5, 3.5)
,它将扩展为(我在注释中添加了参数名称):
__START(/*op=*/ MIN, /*A=*/ 1.5, /*B=*/ 2.5, /*C=*/ 3.5, /*D=*/ 4, /*N=*/ 3, 2, 1)
然后__START
将扩展为__ARGS_3
,以下扩展是无关紧要的。
现在可以清楚地看到参数是如何“计数”的,以及它是如何工作的。您可以轻松实现具有其他功能的相同宏并增加参数的最大数量,例如sum
:
#define __SUM(A, B) ((A)+(B))
#define sum(...) __START(SUM, __VA_ARGS__, 4, 3, 2, 1)
认为它没有min
/ max
有用。
P.S。如果使用Visual C ++,则需要添加一些解决方法(例如第一篇文章中的PP_EXPAND
)以克服VC ++预处理程序错误see for details。我使用了GCC,不需要它。