C++ ときどき ごはん、わりとてぃーぶれいく☆

USAGI.NETWORKのなかのひとのブログ。主にC++。

MSVC++ BUG: C Preprocessor is not capable empty argument

MSVC++(2017; cl.exe-19.11.25547) で C プリプロセッサーのマクロが空の引数を受け付けない C++11/14/17, C99/11 に対する規格違反を報告しました。

概要

#define X( X0 ) something ## X0 () が定義される時、引数が空の呼び出し X() は「空のトークンの引数」を受け付ける事になった C++11 (C99) 以降の言語規格に従えば something() に展開されるべきだが、該当バージョンの現行最新 MSVC++ ではマクロの展開が期待通り行われるエラーとされる。

再現

// compile this code in the MSVC++-19.11.25547
// Expected: compilable
// Actual: not compilable; see the comment below

#include <cstdio>

#define Y( Y0, Y1 ) something ## Y0 ## Y1 ()
#define X( X0 ) something ## X0 ()

void something() { puts( "(n/a)" ); }
void somethingFoo() { puts( "Foo" ); }
void somethingBar() { puts( "Bar" ); }
void somethingFooBar() { puts( "FooBar" ); }

int main()
{
  Y( Foo, Bar );
  Y( Foo, ); // <-- C99 capable, MSVC++ is compilable
  Y( , Bar ); // <-- C99 capable, MSVC++ is compilable
  Y( , ); // <-- C99 capable, MSVC++ is compilable
  X( FooBar );
  X( ); // <-- C99 capable, MSVC++ is NOT compilable
}

この問題の影響

  1. 言語規格違反
  2. Y(,) パターンのような回避策を強いられる。
  3. Microsoft プラットフォームのため『だけ』に追加のコーディングコストを強いられる。

だるい・x・