Maison > développement back-end > C++ > le corps du texte

Pourquoi l'expansion des macros variadiques diffère-t-elle entre MSVC et GCC ?

Patricia Arquette
Libérer: 2024-11-05 08:36:02
original
1113 Les gens l'ont consulté

Why Does Variadic Macro Expansion Differ Between MSVC   and GCC?

Extension de macro variadique dans MSVC

Le mécanisme de macro variadique dans MSVC se comporte différemment de celui de GCC, ce qui entraîne des difficultés pour développer des macros avec plusieurs arguments. Considérez les macros suivantes :

<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>
Copier après la connexion

Dans GCC, cette macro s'étendrait à :

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

  Base * parent;
}</code>
Copier après la connexion

Cependant, dans MSVC, elle s'étendrait à :

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

  Base * parent;
}</code>
Copier après la connexion

Explication

Le problème se pose car MSVC applique l'expansion des macros niveau par niveau, tandis que GCC étend complètement les macros en un seul passage. Considérez l'invocation de la macro :

<code class="cpp">EXPAND_THESE(Property1, Property2, Property3, Property4)</code>
Copier après la connexion
  • MSVC :

    1. VA_NARGS(Property1, Property2, Property3, Property4) -> 4
    2. SEMI_EXPANDED(4, Propriété1, Propriété2, Propriété3, Propriété4) -> MAC4(Propriété1, Propriété2, Propriété3, Propriété4)
    3. EXPAND_THESE(MAC4(Propriété1, Propriété2, Propriété3, Propriété4)) -> MAC4(Propriété1, Propriété2, Propriété3, Propriété4)
  • GCC :

    1. VA_NARGS(Propriété1, Propriété2, Propriété3, Propriété4) -> 4
    2. SEMI_EXPANDED(4, Propriété1, Propriété2, Propriété3, Propriété4) -> MAC4(Propriété1, Propriété2, Propriété3, Propriété4)
    3. EXPAND_THESE(MAC4(Propriété1, Propriété2, Propriété3, Propriété4)) -> MAC4 (Propriété1, Propriété2, Propriété3, Propriété4)
      ---> Déplie davantage la macro MAC4
      ---> Équivalent à plusieurs lignes d'appels ACTUAL_MACRO

Solution de contournement

Pour obtenir un comportement similaire à GCC, on peut utiliser l'approche de Jeff Walden, qui implique de créer des assistants de macro supplémentaires et d'utiliser la macro COUNT_ARGS_MAX5 pour déterminer le nombre d'arguments :

<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>
Copier après la connexion

Alternativement, l'abstraction fournie par la macro "GLUE" peut être utilisée pour simplifier la solution de contournement :

<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>
Copier après la connexion

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal