wake-up-neo.com

Überladen des Makros bei Anzahl der Argumente

Ich habe zwei Makros FOO2 Und FOO3:

#define FOO2(x,y) ...
#define FOO3(x,y,z) ...

Ich möchte ein neues Makro FOO wie folgt definieren:

#define FOO(x,y) FOO2(x,y)
#define FOO(x,y,z) FOO3(x,y,z)

Dies funktioniert jedoch nicht, da Makros die Anzahl der Argumente nicht überladen.

Ohne Änderung von FOO2 Und FOO3 Gibt es eine Möglichkeit, ein Makro FOO zu definieren (mit __VA_ARGS__ Oder auf andere Weise), um den gleichen Effekt wie beim Versenden von FOO(x,y) auf FOO2 und FOO(x,y,z) auf FOO3?

165
Andrew Tomazos

Einfach wie:

#define GET_MACRO(_1,_2,_3,NAME,...) NAME
#define FOO(...) GET_MACRO(__VA_ARGS__, FOO3, FOO2)(__VA_ARGS__)

Also, wenn Sie diese Makros haben:

FOO(World, !)         # expands to FOO2(World, !)
FOO(foo,bar,baz)      # expands to FOO3(foo,bar,baz)

Wenn Sie einen vierten möchten:

#define GET_MACRO(_1,_2,_3,_4,NAME,...) NAME
#define FOO(...) GET_MACRO(__VA_ARGS__, FOO4, FOO3, FOO2)(__VA_ARGS__)

FOO(a,b,c,d)          # expeands to FOO4(a,b,c,d)

Wenn Sie FOO2, FOO3 Und FOO4 Definieren, wird die Ausgabe natürlich durch die der definierten Makros ersetzt.

230
netcoder

Um die Antwort von netcoder zu ergänzen, KÖNNEN Sie dies tatsächlich mit einem Makro mit 0 Argumenten tun, mit Hilfe des GCC ##__VA_ARGS__ Erweiterung:

#define GET_MACRO(_0, _1, _2, NAME, ...) NAME
#define FOO(...) GET_MACRO(_0, ##__VA_ARGS__, FOO2, FOO1, FOO0)(__VA_ARGS__)
42
augurar

Hier ist eine allgemeinere Lösung:

// get number of arguments with __NARG__
#define __NARG__(...)  __NARG_I_(__VA_ARGS__,__RSEQ_N())
#define __NARG_I_(...) __ARG_N(__VA_ARGS__)
#define __ARG_N( \
      _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
     _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
     _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
     _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
     _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
     _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
     _61,_62,_63,N,...) N
#define __RSEQ_N() \
     63,62,61,60,                   \
     59,58,57,56,55,54,53,52,51,50, \
     49,48,47,46,45,44,43,42,41,40, \
     39,38,37,36,35,34,33,32,31,30, \
     29,28,27,26,25,24,23,22,21,20, \
     19,18,17,16,15,14,13,12,11,10, \
     9,8,7,6,5,4,3,2,1,0

// general definition for any function name
#define _VFUNC_(name, n) name##n
#define _VFUNC(name, n) _VFUNC_(name, n)
#define VFUNC(func, ...) _VFUNC(func, __NARG__(__VA_ARGS__)) (__VA_ARGS__)

// definition for FOO
#define FOO(...) VFUNC(FOO, __VA_ARGS__)

Definieren Sie Ihre Funktionen:

#define FOO2(x, y) ((x) + (y))
#define FOO3(x, y, z) ((x) + (y) + (z))

// it also works with C functions:
int FOO4(int a, int b, int c, int d) { return a + b + c + d; }

Jetzt können Sie FOO mit 2, 3 und 4 Argumenten verwenden:

FOO(42, 42) // will use makro function FOO2
FOO(42, 42, 42) // will use makro function FOO3
FOO(42, 42, 42, 42) // will call FOO4 function

Einschränkungen

  • Nur bis zu 63 Argumente (aber erweiterbar)
  • Funktion für kein Argument nur in GCC möglich

Ideen

Verwenden Sie es für Standardargumente:

#define func(...) VFUNC(func, __VA_ARGS__)
#define func2(a, b) func4(a, b, NULL, NULL)
#define func3(a, b, c) func4(a, b, c, NULL)

// real function:
int func4(int a, int b, void* c, void* d) { /* ... */ }

Verwenden Sie es für Funktionen mit einer unendlichen Anzahl von Argumenten:

#define SUM(...) VFUNC(SUM, __VA_ARGS__)
#define SUM2(a, b) ((a) + (b))
#define SUM3(a, b, c) ((a) + (b) + (c))
#define SUM4(a, b, c) ((a) + (b) + (c) + (d))
// ...

PS: __NARG__ wird kopiert von: https://groups.google.com/group/comp.std.c/browse_thread/thread/77ee8c8f92e4a3fb/346fc464319b1ee5?pli=1

31
R1tschY

Ich habe das nur selbst recherchiert und bin auf dieses hier gestoßen. Der Autor hat die Unterstützung von Standardargumenten für C-Funktionen über Makros hinzugefügt.

Ich werde versuchen, den Artikel kurz zusammenzufassen. Grundsätzlich müssen Sie ein Makro definieren, das Argumente zählen kann. Dieses Makro gibt 2, 1, 0 oder einen beliebigen Bereich von Argumenten zurück, die es unterstützen kann. Z.B:

#define _ARG2(_0, _1, _2, ...) _2
#define NARG2(...) _ARG2(__VA_ARGS__, 2, 1, 0)

Dazu müssen Sie ein anderes Makro erstellen, das eine variable Anzahl von Argumenten akzeptiert, die Argumente zählt und das entsprechende Makro aufruft. Ich habe Ihr Beispielmakro genommen und es mit dem Beispiel des Artikels kombiniert. Ich habe die FOO1-Aufruffunktion a() und die FOO2-Aufruffunktion a mit Argument b (offensichtlich gehe ich hier von C++ aus, aber Sie können das Makro beliebig ändern).

#define FOO1(a) a();
#define FOO2(a,b) a(b);

#define _ARG2(_0, _1, _2, ...) _2
#define NARG2(...) _ARG2(__VA_ARGS__, 2, 1, 0)

#define _ONE_OR_TWO_ARGS_1(a) FOO1(a)
#define _ONE_OR_TWO_ARGS_2(a, b) FOO2(a,b)

#define __ONE_OR_TWO_ARGS(N, ...) _ONE_OR_TWO_ARGS_ ## N (__VA_ARGS__)
#define _ONE_OR_TWO_ARGS(N, ...) __ONE_OR_TWO_ARGS(N, __VA_ARGS__)

#define FOO(...) _ONE_OR_TWO_ARGS(NARG2(__VA_ARGS__), __VA_ARGS__)

Also, wenn Sie haben

FOO(a)
FOO(a,b)

Der Präprozessor erweitert dies auf

a();
a(b);

Ich würde auf jeden Fall den Artikel lesen, den ich verlinkt habe. Es ist sehr informativ und er erwähnt, dass NARG2 nicht mit leeren Argumenten funktionieren wird. Er geht dem nach hier .

14
lhumongous

Hier ist eine kompaktere Version von die Antwort oben . Mit Beispiel.

#include <iostream>
using namespace std;

#define OVERLOADED_MACRO(M, ...) _OVR(M, _COUNT_ARGS(__VA_ARGS__)) (__VA_ARGS__)
#define _OVR(macroName, number_of_args)   _OVR_EXPAND(macroName, number_of_args)
#define _OVR_EXPAND(macroName, number_of_args)    macroName##number_of_args

#define _COUNT_ARGS(...)  _ARG_PATTERN_MATCH(__VA_ARGS__, 9,8,7,6,5,4,3,2,1)
#define _ARG_PATTERN_MATCH(_1,_2,_3,_4,_5,_6,_7,_8,_9, N, ...)   N


//Example:
#define ff(...)     OVERLOADED_MACRO(ff, __VA_ARGS__)
#define ii(...)     OVERLOADED_MACRO(ii, __VA_ARGS__)

#define ff3(c, a, b) for (int c = int(a); c < int(b); ++c)
#define ff2(c, b)   ff3(c, 0, b)

#define ii2(a, b)   ff3(i, a, b)
#define ii1(n)      ii2(0, n)


int main() {
    ff (counter, 3, 5)
        cout << "counter = " << counter << endl;
    ff (abc, 4)
        cout << "abc = " << abc << endl;
    ii (3)
        cout << "i = " << i << endl;
    ii (100, 103)
        cout << "i = " << i << endl;


    return 0;
}

Lauf:

[email protected] 13:06:16 /c/T
$ g++ test_overloaded_macros.cpp 

[email protected] 13:16:26 /c/T
$ ./a.exe
counter = 3
counter = 4
abc = 0
abc = 1
abc = 2
abc = 3
i = 0
i = 1
i = 2
i = 100
i = 101
i = 102

Beachten Sie, dass sowohl _OVR Als auch _OVR_EXPAND Redundant aussehen können, der Präprozessor jedoch den Teil _COUNT_ARGS(__VA_ARGS__) erweitern muss, der ansonsten als Zeichenfolge behandelt wird.

6
Evgeni Sergeev

Vielleicht können Sie dieses Makro verwenden, um Anzahl der Argumente zu zählen .

#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, 5,4,3,2,1)
#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,N,...) N
3
eyalm

Hier ist ein Ableger von Evgeni Sergeevs Antwort. Dieser unterstützt auch Null-Argument-Überladungen!

Ich habe das mit GCC und MinGW getestet. Es sollte mit alten und neuen Versionen von C++ funktionieren. Beachten Sie, dass ich es für MSVC nicht garantieren würde ... Aber mit einigen Optimierungen bin ich zuversichtlich, dass es auch dazu gebracht werden könnte, damit zu arbeiten.

Ich habe es auch formatiert, um es in eine Header-Datei (die ich macroutil.h nannte) einzufügen. Wenn Sie dies tun, können Sie einfach diesen Header einbinden, was auch immer Sie für die Funktion benötigen, und nicht die Unangenehmkeit, die mit der Implementierung verbunden ist.

#ifndef MACROUTIL_H
#define MACROUTIL_H

//-----------------------------------------------------------------------------
// OVERLOADED_MACRO
//
// used to create other macros with overloaded argument lists
//
// Example Use:
// #define myMacro(...) OVERLOADED_MACRO( myMacro, __VA_ARGS__ )
// #define myMacro0() someFunc()
// #define myMacro1( arg1 ) someFunc( arg1 )
// #define myMacro2( arg1, arg2 ) someFunc( arg1, arg2 )
//
// myMacro();
// myMacro(1);
// myMacro(1,2);
//
// Note the numerical suffix on the macro names,
// which indicates the number of arguments.
// That is the REQUIRED naming convention for your macros.
//
//-----------------------------------------------------------------------------

// OVERLOADED_MACRO
// derived from: https://stackoverflow.com/questions/11761703/overloading-macro-on-number-of-arguments
// replaced use of _COUNT_ARGS macro with VA_NUM_ARGS defined below
// to support of zero argument overloads
#define OVERLOADED_MACRO(M, ...) _OVR(M, VA_NUM_ARGS(__VA_ARGS__)) (__VA_ARGS__)
#define _OVR(macroName, number_of_args)   _OVR_EXPAND(macroName, number_of_args)
#define _OVR_EXPAND(macroName, number_of_args)    macroName##number_of_args
//#define _COUNT_ARGS(...)  _ARG_PATTERN_MATCH(__VA_ARGS__, 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1)
#define _ARG_PATTERN_MATCH(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15, N, ...)   N

// VA_NUM_ARGS
// copied from comments section of:
// http://efesx.com/2010/07/17/variadic-macro-to-count-number-of-arguments/
// which itself was derived from:
// https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/
#define _ARG16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) _15
#define HAS_COMMA(...) _ARG16(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0)
#define HAS_NO_COMMA(...) _ARG16(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1)
#define _TRIGGER_PARENTHESIS_(...) ,

#define HAS_ZERO_OR_ONE_ARGS(...) \
    _HAS_ZERO_OR_ONE_ARGS( \
    /* test if there is just one argument, eventually an empty one */ \
    HAS_COMMA(__VA_ARGS__), \
    /* test if _TRIGGER_PARENTHESIS_ together with the argument adds a comma */ \
    HAS_COMMA(_TRIGGER_PARENTHESIS_ __VA_ARGS__), \
    /* test if the argument together with a parenthesis adds a comma */ \
    HAS_COMMA(__VA_ARGS__ (~)), \
    /* test if placing it between _TRIGGER_PARENTHESIS_ and the parenthesis adds a comma */ \
    HAS_COMMA(_TRIGGER_PARENTHESIS_ __VA_ARGS__ (~)) \
    )

#define PASTE5(_0, _1, _2, _3, _4) _0 ## _1 ## _2 ## _3 ## _4
#define _HAS_ZERO_OR_ONE_ARGS(_0, _1, _2, _3) HAS_NO_COMMA(PASTE5(_IS_EMPTY_CASE_, _0, _1, _2, _3))
#define _IS_EMPTY_CASE_0001 ,

#define _VA0(...) HAS_ZERO_OR_ONE_ARGS(__VA_ARGS__)
#define _VA1(...) HAS_ZERO_OR_ONE_ARGS(__VA_ARGS__)
#define _VA2(...) 2
#define _VA3(...) 3
#define _VA4(...) 4
#define _VA5(...) 5
#define _VA6(...) 6
#define _VA7(...) 7
#define _VA8(...) 8
#define _VA9(...) 9
#define _VA10(...) 10
#define _VA11(...) 11
#define _VA12(...) 12
#define _VA13(...) 13
#define _VA14(...) 14
#define _VA15(...) 15
#define _VA16(...) 16

#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, PP_RSEQ_N(__VA_ARGS__) )
#define VA_NUM_ARGS_IMPL(...) VA_NUM_ARGS_N(__VA_ARGS__)

#define VA_NUM_ARGS_N( \
    _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
    _11,_12,_13,_14,_15,_16,N,...) N

#define PP_RSEQ_N(...) \
    _VA16(__VA_ARGS__),_VA15(__VA_ARGS__),_VA14(__VA_ARGS__),_VA13(__VA_ARGS__), \
    _VA12(__VA_ARGS__),_VA11(__VA_ARGS__),_VA10(__VA_ARGS__), _VA9(__VA_ARGS__), \
    _VA8(__VA_ARGS__),_VA7(__VA_ARGS__),_VA6(__VA_ARGS__),_VA5(__VA_ARGS__), \
    _VA4(__VA_ARGS__),_VA3(__VA_ARGS__),_VA2(__VA_ARGS__),_VA1(__VA_ARGS__), \
    _VA0(__VA_ARGS__)

//-----------------------------------------------------------------------------

#endif // MACROUTIL_H
1
BuvinJ

Dies scheint auf GCC, Clang und MSVC gut zu funktionieren. Es ist eine aufgeräumte Version einiger der Antworten hier

#define _my_BUGFX(x) x

#define _my_NARG2(...) _my_BUGFX(_my_NARG1(__VA_ARGS__,_my_RSEQN()))
#define _my_NARG1(...) _my_BUGFX(_my_ARGSN(__VA_ARGS__))
#define _my_ARGSN(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,N,...) N
#define _my_RSEQN() 10,9,8,7,6,5,4,3,2,1,0

#define _my_FUNC2(name,n) name ## n
#define _my_FUNC1(name,n) _my_FUNC2(name,n)
#define GET_MACRO(func,...) _my_FUNC1(func,_my_BUGFX(_my_NARG2(__VA_ARGS__))) (__VA_ARGS__)
0
Rian Quinn