C++断言:断言宏中表达式的优先级

igb*_*tiz 18 c++ assert operator-precedence c-preprocessor

在C++中:

  assert(  std::is_same<int , int>::value  ); // does not compile

  assert( (std::is_same<int , int>::value) ); // compiles
Run Code Online (Sandbox Code Playgroud)

有谁能解释为什么?

Bri*_*ian 14

assert是一个预处理器宏.预处理器宏是愚蠢的; 他们不懂模板.预处理器在括号内看到10个令牌:

assert( std :: is_same < int , int > :: value );
Run Code Online (Sandbox Code Playgroud)

它以逗号分开.它不知道这是错误的分裂位置,因为它不理解它std::is_same<int并且int>::value不是有效的C++表达式.

预处理器非常智能,不会跨多个参数分解内部括号对的内容.这就是为什么添加额外的括号可以解决问题.

  • 另外一个`static_assert`就足够了:`static_assert(std :: is_same <int,int> :: value,"oops");` (5认同)

Sha*_*our 11

逗号被视为宏的参数分隔符,但第二种情况下的括号保护参数.我们可以通过参考草案C++标准部分16.3 宏替换来看到这一点(强调我的):

由最外部匹配括号限定的预处理标记序列形成类似函数的宏的参数列表.列表中的各个参数由逗号预处理标记分​​隔,但匹配内部括号之间的逗号预处理标记不会分隔参数.如果在参数列表中有预处理标记序列,否则它们将充当预处理指令,154行为未定义

我们可以看到宏扩展发生在语义分析之前,请参阅2.2 翻译阶段,并看到阶段4包括:

执行预处理指令,扩展宏调用,然后删除所有预处理指令.

第7阶段包括:

[...]每个预处理令牌都转换为令牌.(2.7).由此产生的标记在语法和语义上进行分析并翻译为翻译单元[...]

作为旁注,我们可以看到Boost包含一个特殊的宏来处理这种情况:BOOST_PP_COMMA:

BOOST_PP_COMMA宏扩展为逗号.

并说:

预处理器将逗号解释为宏调用中的参数分隔符.因此,逗号需要特殊处理.

一个例子:

BOOST_PP_IF(1, BOOST_PP_COMMA, BOOST_PP_EMPTY)() // expands to ,
Run Code Online (Sandbox Code Playgroud)