灵感来自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
不起作用,而与第一个的唯一根本区别是它提供的是引用,而不是值?
最佳答案
与常量表达式一样,我们需要查阅[expr.const]中的列表,看看我们编写的任何子表达式是否是不允许的。在这种情况下,相关的项目符号是:
2.11 an id-expression that refers to a variable or data member of reference type unless the reference has a preceding initialization and either
- it is initialized with a constant expression or
- its lifetime began within the evaluation of
e
;
这就是将ref
从水中敲出来的原因。它不会随着 count(ref)
的计算而存在,因为它是预先声明的,并且它不是用常量表达式初始化的。这可能是 7
,但实际的初始化程序是一个临时对象,因为那是引用绑定(bind)的对象。
至于value
是否可用。这是因为没有项目符号不允许 value
本身。现在,引用参数的生命周期从 count(value)
的计算开始,而不是提前。因此,它是在常量表达式中创建的有效引用,但它不能用于读取值
。
关于c++ - 为什么 constexpr 函数对于引用的行为有所不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58472449/