Reference initialization and constant expressions

牧云@^-^@ 提交于 2020-01-14 08:13:29

问题


As a followup to this question, gcc and clang both consider this program ill-formed:

int main() {
    const int& ri = 0;
    constexpr int i = ri;
}

The error is about the value of ri being unusable in a constant expression. 0 is certainly a core constant expression, and as a prvalue core constant expression seems to satisfy these constraints (trivially, since int isn't of class, pointer, or array type). So shouldn't ri satisfy this criteria?

The same is true if I use a prvalue literal of class type:

struct X { };
int main() {
    const X& rx = X{};
    constexpr X x = rx;
}

回答1:


In this statement:

const int& ri = 0;

0 is a prvalue, but ri isn't initialized from that prvalue. The prvalue first undergoes a temporary materialization conversion and the reference is bound to the resulting glvalue. Since ri is bound to this materialized glvalue, and not directly to the prvalue like you (I) suspected, the relevant restrictions are not the prvalue core constant expression restrictions (which 0 does satisfy) but rather the glvalue core constant expression restrictions - that the entity be a permitted result of a constant expression. That restriction, spelled with slightly improved clarity, is:

either an object with static storage duration that is:

  • not a temporary object, or
  • a temporary object whose value satisfies the above constraints,

or it is a function.

Our glvalue is a temporary object whose value satisfies "the above constraints" ("above" here referring to the prvalue core constant restrictions, which int trivially satisfies), but it does not have static storage duration.

Not having static storage duration → the entity is not a permitted result of a constant expression → the glvalue expression not a constant expression → ri wasn't initialized with a constant expression → ri can't be used in a core constant expression → the declaration of i is ill-formed.

The same argument holds for appropriate class types as well.




回答2:


As you pointed out, 2.11 states that a core constant expression must not evaluate to:

  • 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

And further expr.const#6:

A constant expression is either a glvalue core constant expression that refers to an entity that is a permitted result of a constant expression (as defined below), or a prvalue core constant expression whose value satisfies the following constraints:

...

An entity is a permitted result of a constant expression if it is an object with static storage duration that is either not a temporary object or is a temporary object whose value satisfies the above constraints, or it is a function.

From my reading of this, it means that the RHS of const X& r = (substitute X for some type) must either be an object with static storage duration or a temporary object that meets the above criteria. Since an int does not fit either an object of class type, a pointer type or class/array type, it does not qualify.



来源:https://stackoverflow.com/questions/47910988/reference-initialization-and-constant-expressions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!