MSVC の可変個引数マクロ展開が GCC と異なるのはなぜですか? この不一致をどのように克服すればよいでしょうか?

Barbara Streisand
リリース: 2024-11-06 09:10:02
オリジナル
796 人が閲覧しました

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

MSVC 可変個引数マクロ拡張

可変個引数マクロは多用途の拡張機能を提供し、マクロ内で複数の引数を処理できるようにします。 GCC では、次のようなマクロは期待どおりに動作します:

<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>
ログイン後にコピー

MSVC 展開動作

ただし、Microsoft の C コンパイラ (MSVC) では、マクロ展開の動作が異なります。 。 MSVC では、各引数を個別に展開するのではなく、すべての引数を 1 つの式に連結します。

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)
ログイン後にコピー

}

ベース * 親;
};

GCC 拡張:

{<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>();</p> <p>}</p> <p>Base *parent;<br>}<br>

MSVC 拡張:

struct MyStructure<br>{<br> void Foo()<br> {</p>
<pre class="brush:php;toolbar:false">parent->GetProperty<Property1, Property2, Property3, Property4>();
ログイン後にコピー

}

Base *parent;
}

解決策:

Jeff Walden は次の回避策を提案しました。次のパターン:

<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>
ログイン後にコピー

このアプローチでは、必要な可変個引数マクロ数 (例: ERROR1、ERROR2 など) ごとに CHOOSE_HELPER マクロを定義する必要があります。ただし、可変個引数マクロの定義の範囲内で各 CHOOSE_HELPER マクロを宣言することが重要です。

より簡潔で移植可能な解決策は、次の手法を利用することです。

<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>
ログイン後にコピー

この設定では、マクロは次のように定義できます:

<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>
ログイン後にコピー

OVERLOAD_MACRO 階層を使用すると、CHOOSE_HELPER マクロの定義を回避できます。

以上がMSVC の可変個引数マクロ展開が GCC と異なるのはなぜですか? この不一致をどのように克服すればよいでしょうか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
前の記事:Qt でカスタム クラスをシリアル化するにはどうすればよいですか? 次の記事:文字列リテラル内に二重引用符を含めるにはどうすればよいですか?
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
最新の問題
関連トピック
詳細>
人気のおすすめ
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!