MSVC と GCC で可変引数マクロ展開が異なるのはなぜですか?

Patricia Arquette
リリース: 2024-11-05 08:36:02
オリジナル
931 人が閲覧しました

Why Does Variadic Macro Expansion Differ Between MSVC   and GCC?

MSVC での可変個引数マクロの展開

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

GCC では、このマクロは次のように展開されます:

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

  Base * parent;
}</code>
ログイン後にコピー

ただし、MSVC では、次のように展開されます:

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

  Base * parent;
}</code>
ログイン後にコピー

説明

MSVC がマクロ拡張を適用するために問題が発生します。 GCC はマクロを 1 パスで完全に展開しますが、レベルごとに展開されます。次のマクロ呼び出しを考えてみましょう。

<code class="cpp">EXPAND_THESE(Property1, Property2, Property3, Property4)</code>
ログイン後にコピー
  • MSVC :

    1. VA_NARGS(Property1, Property2, Property3, Property4) -> 4
    2. SEMI_EXPANDED(4, プロパティ 1, プロパティ 2, プロパティ 3, プロパティ 4) -> MAC4(プロパティ1, プロパティ2, プロパティ3, プロパティ4)
    3. EXPAND_THESE(MAC4(プロパティ1, プロパティ2, プロパティ3, プロパティ4)) ->; MAC4(プロパティ1, プロパティ2, プロパティ3, プロパティ4)
  • GCC:

    1. VA_NARGS(プロパティ1, プロパティ2, プロパティ3,プロパティ4) -> 4
    2. SEMI_EXPANDED(4, プロパティ 1, プロパティ 2, プロパティ 3, プロパティ 4) -> MAC4(プロパティ1, プロパティ2, プロパティ3, プロパティ4)
    3. EXPAND_THESE(MAC4(プロパティ1, プロパティ2, プロパティ3, プロパティ4)) ->; MAC4(プロパティ1, プロパティ2, プロパティ3, プロパティ4)
      --> MAC4 マクロ
      --> をさらに展開します。複数行の ACTUAL_MACRO 呼び出しに相当します

回避策

GCC と同様の動作を実現するには、Jeff Walden のアプローチを使用できます。追加のマクロ ヘルパーを作成し、COUNT_ARGS_MAX5 マクロを使用して、引数:

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

または、「GLUE」マクロによって提供される抽象化を使用して、回避策を簡略化することもできます:

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

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

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