GCC/CLANG 预处理器与 MSVC 之间的差异是什么?

What are the deviations between preprocessors of GCC/CLANG vs MSVC?

以下预处理器宏(通常怀疑:测试空参数列表和计算参数数量)运行 在 gcc/clang 上没有警告但在 Microsoft VisualC 上失败:

// IS_EMPTY() returns nothing if the parameter list is empty and a single ',' (comma) otherwise.
// The parameter list can have up to 32 parameters
#define IS_EMPTY(...) IS_EMPTY1(__VA_ARGS__)
#define IS_EMPTY1(...) IS_EMPTY2(DROP_PARAMS  __VA_ARGS__ (,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,EMPTY))
#define IS_EMPTY2(...) IS_EMPTY3(__VA_ARGS__)
#define IS_EMPTY3(f,...) TEST_EMPTY_##f )
#define DROP(...)
#define DROP_PARAMS(...) DROP_PARAMS1(__VA_ARGS__,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,)
#define DROP_PARAMS1(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,_32,__m,...) CATCH_##__m
#define TEST_EMPTY_DROP_PARAMS , DROP(
#define TEST_EMPTY_CATCH_EMPTY DROP(
#define TEST_EMPTY_CATCH_ , DROP(


//--- testcode below ---
#define TEST_EMPTY(...) __VA_ARGS__ : TAKE_2ND(IS_EMPTY(__VA_ARGS__) not,) empty
#define TAKE_2ND(...) TAKE_2ND_(__VA_ARGS__,,)
#define TAKE_2ND_(f,s,...) s

TEST_EMPTY()
TEST_EMPTY(a.b.)
TEST_EMPTY(A)
TEST_EMPTY(())
TEST_EMPTY(int()(more))
TEST_EMPTY((int))
TEST_EMPTY(foo bar)
TEST_EMPTY(*)

#define FOO(x) x
#define BAR
TEST_EMPTY(FOO(BAR))
TEST_EMPTY(1,2)
TEST_EMPTY(1.)
TEST_EMPTY(.1)
TEST_EMPTY(1,)
TEST_EMPTY((int)(float))
TEST_EMPTY(() this)
TEST_EMPTY(() is, () not ()  empty ())
TEST_EMPTY(,notempty)
TEST_EMPTY((),notempty)
TEST_EMPTY((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,))

clang 和 gcc 的输出:

: empty
a.b. : not empty
A : not empty
() : not empty
int()(more) : not empty
(int) : not empty
foo bar : not empty
* : not empty



: empty
1,2 : not empty
1. : not empty
.1 : not empty
1, : not empty
(int)(float) : not empty
() this : not empty
() is, () not () empty () : not empty
,notempty : not empty
(),notempty : not empty
(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,) : not empty

MSVC 上的输出:

 :  empty
a.b. :  empty
A :  empty
() :  empty
int()(more) :  empty
(int) :  empty
foo bar :  empty
* :  empty



 :  empty
1,2 :  empty
1. :  empty
.1 :  empty
1, :  empty
(int)(float) :  empty
() this :  empty
() is, () not () empty () :  empty
,notempty :  empty
(),notempty :  empty
(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,) :  empty

由于 MSVC 完全沉默,我想知道我的解决方案还有多远。还是 MSVC 的行为不正确?

Microsoft 的 Visual C++ 预处理器已知 compliance 问题。

他们重写了预处理器,但默认情况下启用旧的预处理器。要启用,希望更符合select这个选项:

/实验:预处理器

从 Visual Studio 2017 15.8 Preview 3 版本开始。

我运行使用选项的宏:/experimental:preprocessor在最新发布的版本15.8.9上,结果如下:

: empty
a.b. : not empty
A : not empty
() : not empty
int()(more) : not empty
(int) : not empty
foo bar : not empty
* : not empty


: empty
1, 2 : not empty
1. : not empty
.1 : not empty
1, : not empty
(int)(float) : not empty
() this : not empty
() is, () not () empty() : not empty
, notempty : not empty
(), notempty : not empty
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, ) : not empty

错误的 "empty" 现在是 "not empty" 并且与 GCC 和 Clang 的预处理器一致。