受到Counting function arguments at compile time
的启发考虑this code:
template <typename... Args>
constexpr int count(Args&&...)
{
return sizeof...(Args);
}
void foo(int value)
{
static_assert(count(value) >= 0); // OK
const int& ref = 7;
static_assert(count(ref) >= 0); // Error
}
第一个static_assert
工作正常。第二个错误:
<source>:12:19: error: static_assert expression is not an integral constant expression
static_assert(count(ref) >= 0);
^~~~~~~~~~~~~~~
<source>:12:25: note: initializer of 'ref' is not a constant expression
static_assert(count(ref) >= 0);
^
<source>:11:16: note: declared here
const int& ref = 7;
^
两种情况都令我惊讶。为什么在编译时显然不知道static_assert
的情况下,第一个value
可以正常工作?为什么第二个static_assert
不起作用,而与第一个{唯一的根本区别是它提供了引用而不是值?
答案 0 :(得分:3)
与常量表达式一样,我们需要查阅 [expr.const] 中的列表,看看是否禁止编写任何子表达式。在这种情况下,相关的项目符号就是这个:
2.11一个id表达式,它引用引用类型的变量或数据成员,除非引用具有前面的初始化,并且 要么
- 使用常量表达式或
进行初始化- 其寿命始于
e
的评估;
这就是将ref
击倒的原因。由于count(ref)
的赋值是事先声明的,因此它不存在于求值中,并且未使用常量表达式进行初始化。可能是7
,但是实际的初始化程序是一个临时对象,因为这是引用绑定的对象。
对于value
可用。这是因为没有禁止value
本身的项目符号。现在,引用参数的生命周期始于对count(value)
的求值,而不是事先求值。因此,这是在常量表达式中创建的有效引用,但不能用于读取value
。