Heim > Backend-Entwicklung > C++ > Hauptteil

Warum unterscheidet sich die Variadic-Makroerweiterung zwischen MSVC und GCC?

Patricia Arquette
Freigeben: 2024-11-05 08:36:02
Original
931 Leute haben es durchsucht

Why Does Variadic Macro Expansion Differ Between MSVC   and GCC?

Variadische Makroerweiterung in MSVC

Der variadische Makromechanismus in MSVC verhält sich anders als der in GCC, was zu Schwierigkeiten bei der Erweiterung von Makros führt mehrere Argumente. Betrachten Sie die folgenden Makros:

<code class="cpp">#define VA_NARGS_IMPL(_1, _2, _3, _4, _5, N, ...) N
#define VA_NARGS(...) VA_NARGS_IMPL(__VA_ARGS__, 5, 4, 3, 2, 1)

#define FULLY_EXPANDED(count, ...) \
  MAC ## count (__VA_ARGS__)

#define SEMI_EXPANDED(count, ...) FULLY_EXPANDED(count, __VA_ARGS__)

#define EXPAND_THESE(...) SEMI_EXPANDED(VA_NARGS(__VA_ARGS__), __VA_ARGS__)

#define ACTUAL_MACRO(x) parent->GetProperty<x>();
#define MAC1(a) ACTUAL_MACRO(a)
#define MAC2(a,b) MAC1(a) ACTUAL_MACRO(b)
#define MAC3(a,b,c) MAC2(a,b) ACTUAL_MACRO(c)
#define MAC4(a,b,c,d) MAC3(a,b,c) ACTUAL_MACRO(d)
#define MAC5(a,b,c,d,e) MAC4(a,b,c,d) ACTUAL_MACRO(e)</code>
Nach dem Login kopieren

In GCC würde dieses Makro erweitert werden zu:

<code class="cpp">struct MyStructure
{
  void Foo()
  {
    parent->GetProperty<Property1>(); 
    parent->GetProperty<Property2>(); 
    parent->GetProperty<Property3>(); 
    parent->GetProperty<Property4>();
  }

  Base * parent;
}</code>
Nach dem Login kopieren

In MSVC wird es jedoch erweitert zu:

<code class="cpp">struct MyStructure
{
  void Foo()
  {
    parent->GetProperty<Property1, Property2, Property3, Property4>();
  }

  Base * parent;
}</code>
Nach dem Login kopieren

Erklärung

Das Problem entsteht, weil MSVC die Makroerweiterung Ebene für Ebene anwendet, während GCC Makros in einem Durchgang vollständig erweitert. Betrachten Sie den Makroaufruf:

<code class="cpp">EXPAND_THESE(Property1, Property2, Property3, Property4)</code>
Nach dem Login kopieren
  • MSVC :

    1. VA_NARGS(Property1, Property2, Property3, Property4) -> 4
    2. SEMI_EXPANDED(4, Property1, Property2, Property3, Property4) -> MAC4(Eigenschaft1, Eigenschaft2, Eigenschaft3, Eigenschaft4)
    3. EXPAND_THESE(MAC4(Eigenschaft1, Eigenschaft2, Eigenschaft3, Eigenschaft4)) -> MAC4(Eigenschaft1, Eigenschaft2, Eigenschaft3, Eigenschaft4)
  • GCC:

    1. VA_NARGS(Eigenschaft1, Eigenschaft2, Eigenschaft3, Eigenschaft4) -> 4
    2. SEMI_EXPANDED(4, Property1, Property2, Property3, Property4) -> MAC4(Eigenschaft1, Eigenschaft2, Eigenschaft3, Eigenschaft4)
    3. EXPAND_THESE(MAC4(Eigenschaft1, Eigenschaft2, Eigenschaft3, Eigenschaft4)) -> MAC4(Eigenschaft1, Eigenschaft2, Eigenschaft3, Eigenschaft4)
      --> Entfaltet das MAC4-Makro weiter
      --> Entspricht mehreren Zeilen von ACTUAL_MACRO-Aufrufen

Workaround

Um ein ähnliches Verhalten wie GCC zu erreichen, kann man den Ansatz von Jeff Walden anwenden beinhaltet das Erstellen zusätzlicher Makro-Helfer und die Verwendung des COUNT_ARGS_MAX5-Makros, um die Anzahl der Argumente zu bestimmen:

<code class="cpp">#define FOO_CHOOSE_HELPER1(count) FOO##count
#define FOO_CHOOSE_HELPER2(count) FOO_CHOOSE_HELPER1(count)
#define FOO_CHOOSE_HELPER(count) FOO_CHOOSE_HELPER2(count)

#define ERROR(...) GLUE(FOO_CHOOSE_HELPER(COUNT_ARGS_MAX5(__VA_ARGS__)), (__VA_ARGS__))

#define ASSERT1(expr) singleArgumentExpansion(expr)
#define ASSERT2(expr, explain) twoArgumentExpansion(expr, explain)
#define ASSERT(...) GLUE(FOO_CHOOSE_HELPER(COUNT_ARGS_MAX5(__VA_ARGS__)), (__VA_ARGS__))</code>
Nach dem Login kopieren

Alternativ kann die vom „GLUE“-Makro bereitgestellte Abstraktion verwendet werden, um die Problemumgehung zu vereinfachen:

<code class="cpp">#define OVERLOAD_MACRO2(name, count) name##count
#define OVERLOAD_MACRO1(name, count) OVERLOAD_MACRO2(name, count)
#define OVERLOAD_MACRO(name, count) OVERLOAD_MACRO1(name, count)

#define CALL_OVERLOAD(name, ...) GLUE(OVERLOAD_MACRO(name, COUNT_ARGS_MAX5(__VA_ARGS__)), (__VA_ARGS__))

#define ERROR1(title) printf("Error: %s\n", title);
#define ERROR2(title, message) \
    ERROR1(title); \
    printf("Message: %s\n", message);
#define ERROR(...) CALL_OVERLOAD(ERROR, __VA_ARGS__);

#define ASSERT1(expr) singleArgumentExpansion(expr)
#define ASSERT2(expr, explain) twoArgumentExpansion(expr, explain)
#define ASSERT(...) CALL_OVERLOAD(ASSERT, __VA_ARGS__);</code>
Nach dem Login kopieren

Das obige ist der detaillierte Inhalt vonWarum unterscheidet sich die Variadic-Makroerweiterung zwischen MSVC und GCC?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Neueste Artikel des Autors
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!