在C ++ 11中,当表格的预处理指令...
时#if expr
遇到 ...,expr
被评估为constant-expression
,如16.1 [cpp.cond]
中所述。
在expr
上进行宏替换后,将其标识符(和关键字)替换为0,将其preprocessing-tokens
转换为tokens
,defined
运算符进行评估等等。
我的问题是当expr
中的某个令牌是user-defined-literal
时会发生什么?
用户定义的文字与函数调用类似,但函数调用不能在expr
(我认为)中发生,作为标识符替换的副作用。但技术上user-defined-literals
可以存活下来。
我怀疑这是一个错误,但我不明白如何从标准中得出结论?
或许忽略了在第16条[cpp]
上添加用户定义文字的(迂腐)影响?
或者我错过了什么?
更新
通过一个例子澄清:
这预处理的内容是什么:
#if 123_foo + 5.5 > 100
bar
#else
baz
#endif
bar或baz还是错误?
GCC 4.7报告:
test.cpp:1:5: error: user-defined literal in preprocessor expression
所以它认为这是一个错误。这可以参考标准来证明吗?或者这只是“隐含的”?
答案 0 :(得分:3)
在C ++ 11中遇到格式为
#if expr ...
的预处理指令时, 如expr
中所述,constant-expression
被评估为16.1 [cpp.cond]
。这是在
expr
上进行宏替换后完成的,其标识符(和关键字)是。{ 由0
替换,其preprocessing-tokens
转换为tokens
, 评估defined
运算符,依此类推。我的问题是当
tokens
中的一个expr
是a时会发生什么user-defined-literal
?
该计划格式不正确。
我的观点的核心是从16.1/1
脚注147
中的观察中收集到的,在翻译阶段4中除了宏名称之外没有identifiers
。
论据:
根据2.14.8 [lex.ext]/2
user-defined-literal
被视为对literal operator
的调用 或literal operator template
(13.5.8)
。
所以在这里,即使在16.1/4
中描述的所有替换之后,我们仍然有一个(运算符)函数的剩余调用。 (其他尝试,例如使用constexpr
函数,会被identifiers
替换所有非宏0
而受阻。)
正如在翻译阶段4中发生的那样,还有没有定义或甚至声明的函数;尝试查找literal-operator-id
必须失败(请参阅16.1/1
中的脚注147以获得类似的参数)。
从一个略微不同的角度来看,5.19/2
我们发现:
conditional-expression
除非是core constant expression
涉及以下之一作为潜在评估的子表达式 (3.2)[...]:
- [...]
- 为文字类或constexpr函数调用constexpr构造函数以外的函数;
- 调用未定义的constexpr函数或未定义的constexpr构造函数[...];
由此,在user-defined literal
中使用constant expression
需要定义的和 constexpr literal operator
,这又可以'在翻译阶段4可用。
gcc拒绝这一点是正确的。
答案 1 :(得分:0)
在C ++ 11中遇到
#ifdef expr
形式的预处理指令时,expr
被评估为16.1所述的常量表达式。这是在expr上的宏替换之后,其标识符(和关键字)被替换为0,其预处理标记被转换为标记,定义运算符被评估,等等。
没有!
#ifdef
,#ifndef
或defined
的参数未评估。例如,假设我从未#define
预处理器符号SYMBOL_THAT_IS_NEVER_DEFINED
。这完全有效:
#ifdef SYMBOL_THAT_IS_NEVER_DEFINED
code
#endif
扩展未定义符号的符号是非法的。假设SYMBOL_THAT_IS_NEVER_DEFINED
尚未定义,这是非法的:
#if SYMBOL_THAT_IS_NEVER_DEFINED
code
#endif
类似于在解除引用之前检查指针是否为非空,在使用之前检查符号是否合法是合法的:
#if (defined SYMBOL_THAT_MIGHT_BE_DEFINED) && SYMBOL_THAT_MIGHT_BE_DEFINED
code
#endif