5

たとえば、2 つ以上のパラメーターを取ることができる新しい最大/最小マクロを実装したいと考えています。

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

4 に答える 4

6

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__})
于 2014-07-10T16:43:37.187 に答える
3

あなたの質問には答えの半分が含まれています-マクロに示されている手法を使用して、可変引数数でmin/マクロを構築できます(元のコードと同様に、引数の数には制限がありますが、選択できます)。maxPP_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- 2 つの引数だけで必要な操作を実行するマクロ名 (先行する二重アンダースコアなし)
  • A, B, C, - これらの引数は/Dの引数を受け取り、/引数の数が最大 (このサンプル コードでは 4) よりも少ない場合は、ダミーの引数を受け取る可能性があります。minmaxminmax
  • 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

PP_EXPANDPS Visual C++ を使用している場合は、VC++ プリプロセッサのバグを克服するために(最初の投稿のように) いくつかの回避策を追加する必要があります。詳細については、を参照してください。私は GCC を使用しましたが、GCC は必要ありません。

于 2019-07-23T15:07:24.160 に答える
2

同じことを行う 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;
于 2014-04-01T01:45:57.770 に答える
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__)) 

プリプロセッサは展開中の比較を直接サポートしていないため、これらすべてをゼロから実装するのは大変な作業です。ここでの手法を使用して、カウンターと while ループ構造を実装できます。これにより、 に必要な未満 (またはより大きい) を実装できる減算を実装できますMAX。次に、別のものwhileを使用して、バリディアック引数を折りたたむことができます。

最後に、これらすべてをプリプロセッサで行うにはいくつかの制限があります。プリプロセッサのチューリングが完全に完了していません。したがって、ブーストの例では、0 から 256 までの値に制限されます (これは完全にブーストの制限です。自分で行う場合は、その制限を上げることができます)。達成したいことによっては、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...)); 
}
于 2014-04-04T09:23:58.493 に答える