在C ++中:
assert( std::is_same<int , int>::value ); // does not compile
assert( (std::is_same<int , int>::value) ); // compiles
任何人都可以解释原因吗?
答案 0 :(得分:14)
assert
是预处理器宏。预处理器宏是愚蠢的;他们不懂模板。预处理器在括号内看到10个令牌:
assert( std :: is_same < int , int > :: value );
它以逗号分隔。它不知道这是错误的分割位置,因为它不理解std::is_same<int
和int>::value
不是有效的C ++表达式。
预处理器 足够聪明,不会在多个参数中分解内部括号对的内容。这就是为什么添加额外的括号可以解决问题。
答案 1 :(得分: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 ,