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