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