Maison > Article > développement back-end > Pourquoi l'expansion des macros variadiques diffère-t-elle entre MSVC et 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>
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>
Cependant, dans MSVC, elle s'étendrait à :
<code class="cpp">struct MyStructure { void Foo() { parent->GetProperty<Property1, Property2, Property3, Property4>(); } Base * parent; }</code>
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>
MSVC :
GCC :
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>
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>
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!