Можно ли реализовать макрос max или min, который может принимать переменные аргументы (более двух параметров)


Я хочу реализовать новый макрос 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__))
3 3

3 ответа:

В 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__})

Существует алгоритм C++ STL, чтобы сделать то же самое:

Max_element .

Min_element

Начинает использовать их вместо написания макроса для достижения этого:

 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;

С Помощью Boost.Препроцессор , Вы можете реализовать его следующим образом:

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

Поскольку препроцессор не поддерживает сравнение непосредственно во время расширения, это большая работа, чтобы реализовать все это с нуля. Используя методы здесь , Вы можете реализовать счетчик и построить цикл while. При этом вы можете реализовать вычитание, которое позволит вам реализовать меньше(или больше), что необходимо для MAX. Затем с помощью другого while Вы можете сделать складку над варидиакальные аргументы.

Наконец, есть некоторые ограничения для выполнения всего этого в препроцессоре. Препроцессор не является полностью завершенным по Тьюрингу. Таким образом, в Примере boost вы будете ограничены значениями от 0 до 256(это полностью ограничение boost, если вы сделаете это самостоятельно, вы можете поднять это ограничение). В зависимости от того, чего вы хотите достичь, возможно, лучше написать функцию varidiac для max:
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...)); 
}