当其参数是对文字类型的引用时的常量函数

Constant function when its parameter is a reference to literal type

constexpr int func(int const& rf){
   return rf;
}
int main(){
  constexpr int value = func(0);
}

考虑上面的代码,它将被编译并且格式正确,但是我对此感到困惑。根据[[stmt.return#2]]

the return statement initializes the glvalue result or prvalue result object of the (explicit or implicit) function call by copy-initialization from the operand.

所以,我认为 return 语句等同于以下内容:

constexpr void func(int const& rf){
   constexpr int value = rf;  //#1
}
int main(){
   func(0);
}

但是,这次代码格式错误。因为它受这些规则约束:

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;

rf 没有前面的初始化,它的生命周期在进入函数体之前就开始了,因此,当 rf#1 处求值时,它的生命周期不会在这个表情。所以,表达式不是常量表达式,但是,作为等效形式,我想知道为什么当对象 value 从操作数 rf?[=24 复制初始化时,第一个代码是格式正确的=]

更新

我认为这些问题简单地等同于这种形式:

constexpr int func(){
    int result = 0;
    return result;
}

int main()
{
    constexpr int x = func();
}

当对 return 语句的操作数 result 应用左值到右值转换时,将违反以下规则:

an lvalue-to-rvalue conversion unless it is applied to

  • a non-volatile glvalue of integral or enumeration type that refers to a complete non-volatile const object with a preceding initialization, initialized with a constant expression

result 是用常量表达式而不是常量对象初始化的,所以它违反了这个规则并且不是常量表达式。为什么实际上它是格式正确的?为什么 constexpr 函数可以 return 一个非常量变量?到目前为止,我还没有找到任何额外的规则来允许这样做。

So, I think the return statement would be equivalent to the following

如果等同于您的意思是如果它是有效的,它将是复制初始化,那么是的。但它是无效的,所以说它等价是不正确的。

However, as the equivalent form, I wonder why the first code is well-formed when the object value copy-initialized from the operand rf?

因为复制初始化在这里并不重要。

的原因
constexpr int value = func(0);

有效,而

constexpr int value = rf;

不是,完全是由于初始化中使用的表达式的属性。复制初始化在取消第二个或允许第一个资格方面没有任何作用。

对于第一个例子,func(0)是必须满足常量表达式要求的表达式。它是一个产生纯右值的表达式。该 prvalue 最终是从某个参考中复制初始化的。然而,引用指的是一些仅在不断评估期间存在的对象。 IE。在调用函数之前为保存 0 而创建的“临时”。这就是为什么可以对纯右值结果进行常量计算,然后用于初始化 constexpr 变量。

在第二个例子中,另一方面,rf 不能用在常量表达式中。对于您引用的那一段。 constexpr 函数仍然是常规函数,也可以“在运行时”调用。此外,编译器 没有 常量折叠它们。因此,无论何时评估它们,它们都必须是有效函数。因此,由于 rf 在常量表达式中不可用 irregardless 如何调用函数,它不能用于初始化必须由常量表达式无条件初始化的东西在函数本身内部。

在标准框架中稍微说一下,初始化的完整表达式可以访问在其中创建的对象。在

的背景下
constexpr int value = func(0);

rf 绑定到作为完整表达式的一部分存在的对象。所以我们可以访问它。然而,在

的背景下
constexpr int value = rf;

rf 未绑定到对象整个生命周期开始于 that 完整表达式。

每个constexpr变量声明都是它自己独立的“上下文”,用于检查常量表达式的有效性。他们在这方面彼此脱节。


result is initialized with a constant expression but not a const object, So it violate this rule

它违反了那个要点,但是该子句中有几个要点是有效的左值到右值转换的替代方法。它非常符合

an lvalue-to-rvalue conversion unless it is applied to

  • a non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of e;

result 是文字类型,在 func() 的求值期间生效(以及退出)。因此它是合式的。