Home > Backend Development > C++ > body text

Why does MSVC variadic macro expansion differ from GCC, and how can we overcome this discrepancy?

Barbara Streisand
Release: 2024-11-06 09:10:02
Original
795 people have browsed it

Why does MSVC   variadic macro expansion differ from GCC, and how can we overcome this discrepancy?

MSVC Variadic Macro Expansion

Variadic macros offer versatile expansion capabilities, allowing you to handle multiple arguments within macros. In GCC, macros like the following work as expected:

<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>
Copy after login

MSVC Expansion Behavior

However, in Microsoft's C Compiler (MSVC ), the macro expansion behaves differently. Instead of expanding each argument separately, MSVC concatenates all arguments into a single expression.

struct MyStructure<br>{<br>  void Foo()<br>  {</p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">EXPAND_THESE(Property1, Property2, Property3, Property4)
Copy after login

}

Base * parent;
};

GCC Expansion:

struct MyStructure<br>{<br>  void Foo()<br>  {</p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">parent->GetProperty<Property1>(); 
parent->GetProperty<Property2>(); 
parent->GetProperty<Property3>(); 
parent->GetProperty<Property4>();
Copy after login

}

Base * parent;
}

MSVC Expansion:

struct MyStructure<br>{<br>  void Foo()<br>  {</p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">parent->GetProperty<Property1, Property2, Property3, Property4>();
Copy after login

}

Base * parent;
}

Solution:

Jeff Walden proposed a workaround using the following pattern:

<code class="cpp">#define ERRORn(...) ERROR_CHOOSE_HELPERn(COUNT_ARGS_MAX5(__VA_ARGS__), __VA_ARGS__)
#define ERROR_CHOOSE_HELPER1(count) ERROR1
#define ERROR_CHOOSE_HELPER2(count) ERROR2
#define ERROR_CHOOSE_HELPER(count) ERROR_CHOOSE_HELPER##count</code>
Copy after login

This approach requires defining a CHOOSE_HELPER macro for each desired variadic macro count (e.g., ERROR1, ERROR2, etc.). However, it is essential to declare each CHOOSE_HELPER macro within the scope of the variadic macro's definition.

A more concise and portable solution is to leverage the following technique:

<code class="cpp">#define GLUE(x, y) x y

#define RETURN_ARG_COUNT(_1_, _2_, _3_, _4_, _5_, count, ...) count
#define EXPAND_ARGS(args) RETURN_ARG_COUNT args
#define COUNT_ARGS_MAX5(...) EXPAND_ARGS((__VA_ARGS__, 5, 4, 3, 2, 1, 0))

#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__))</code>
Copy after login

With this setup, macros can be defined as:

<code class="cpp">#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>
Copy after login

By using the OVERLOAD_MACRO hierarchy, it is possible to avoid defining CHOOSE_HELPER macros.

The above is the detailed content of Why does MSVC variadic macro expansion differ from GCC, and how can we overcome this discrepancy?. For more information, please follow other related articles on the PHP Chinese website!

source:php.cn
Previous article:How Can I Serialize a Custom Class with Qt? Next article:How to Include Double Quotes Within a String Literal?
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Latest Issues
Related Topics
More>
Popular Recommendations
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!