是一个constexpr数组必须odr使用下标? [英] Is a constexpr array necessarily odr-used when subscripted?

查看:133
本文介绍了是一个constexpr数组必须odr使用下标?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给定以下代码:

  struct A {static constexpr int a [3] = {1,2,3} ; }; 

int main(){
int a = A :: a [0];
int b [A :: a [1]];
}

A :: a 必须 odr使用 int a = A :: a [0]






注意:此问题表示

首次使用 A :: a



  int a = A :: a [0 ]; 

初始化程序是一个常量表达式,但不会停止 A: :a 从这里使用 odr使用。而且, A :: a 是这个表达式所使用的 odr-use



A :: a [0] 开始,让我们来看看 [basic.def.odr](3.2)/ 3 未来读者,我使用N3936的措辞):


变量 x 在我们的例子中, A :: a ],其名称显示为可能评估的表达式ex [ A :: a ]是 odr使用,除非




  • 将左值到右值转换应用到 x 产生一个常量表达式[b]
    不调用任何非平凡函数[ it does not] and,


  • 如果 x 是对象, >


    • ex 潜在结果表达式 e ,其中左值到右值转换应用于 e e



那么: e 有什么可能的值?表达式的潜在结果集合是表达式的一组子表达式(您可以通过阅读 [basic.def.odr](3.2)/ 2 ),所以我们只需要考虑 ex 是一个子表达式的表达式。这些是:

  A :: a 
A :: a [0]

其中,左值到右值转换立即应用于 A :: a ,因此我们只考虑 A :: a [0] 。根据 [basic.def.odr](3.2)/ 2 A :: a [0] 的潜在结果集为空,因此 A :: a 是由此表达式使用的 odr-used



您可以认为我们首先将 A :: a [0] 重写为 *(A :: a + 0) 。但是没有任何变化: e 的可能值为

  A :: a 
A :: a + 0
(A :: a + 0)
*(A :: a + 0)

其中,只有第四个应用了左值到右值转换,并且 [basic.def.odr] )/ 2 表示 *(A :: a + 0)的潜在结果集为空。特别要注意的是,数组到指针衰减是左值到右值转换( [conv.lval](4.1)),即使它转换数组左值到指针rvalue - 这是一个数组到指针的转换( [conv.array](4.2))。



使用 A :: a



  a [1]]; 

根据标准,这与第一种情况没有什么不同。再次, A :: a [1] 是一个常量表达式,因此这是一个有效的数组边界,但是编译器仍然允许在运行时发出代码来计算这个值,并且数组仍然 odr使用 A :: a



注特别是常数表达式(默认)是潜在评估的表达式。每 [basic.def.odr](3.2)/ 2



[expr](expr) 5)/ 8 只是将我们重定向到其他子类别:


在某些上下文中, .3,5.3.7,7.1.6.2)。


这些子句分别表示一些 typeid

的操作数, code>表达式, sizeof 的操作数, noexcept 的操作数和 decltype 是未求值的操作数。没有其他类型的未经评估的操作数。


Given the following code:

struct A { static constexpr int a[3] = {1,2,3}; };

int main () {
  int a = A::a[0];
  int b  [A::a[1]];
}

is A::a necessarily odr-used in int a = A::a[0]?


Note: This question represents a less flamey/illogical/endless version of a debate in the Lounge.

解决方案

First use of A::a:

int a = A::a[0];

The initializer is a constant expression, but that doesn't stop A::a from being odr-used here. And, indeed, A::a is odr-used by this expression.

Starting from the expression A::a[0], let's walk through [basic.def.odr](3.2)/3 (for future readers, I'm using the wording from N3936):

A variable x [in our case, A::a] whose name appears as a potentially-evaluated expression ex [in our case, the id-expression A::a] is odr-used unless

  • applying the lvalue-to-rvalue conversion to x yields a constant expression [it does] that does not invoke any non-trivial functions [it does not] and,

  • if x is an object [it is],

    • ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion is applied to e, or e is a discarded-value expression.

So: what possible values of e are there? The set of potential results of an expression is a set of subexpressions of the expression (you can check this by reading through [basic.def.odr](3.2)/2), so we only need to consider expressions of which ex is a subexpression. Those are:

A::a
A::a[0]

Of these, the lvalue-to-rvalue conversion is not applied immediately to A::a, so we only consider A::a[0]. Per [basic.def.odr](3.2)/2, the set of potential results of A::a[0] is empty, so A::a is odr-used by this expression.

Now, you could argue that we first rewrite A::a[0] to *(A::a + 0). But that changes nothing: the possible values of e are then

A::a
A::a + 0
(A::a + 0)
*(A::a + 0)

Of these, only the fourth has an lvalue-to-rvalue conversion applied to it, and again, [basic.def.odr](3.2)/2 says that the set of potential results of *(A::a + 0) is empty. In particular, note that array-to-pointer decay is not an lvalue-to-rvalue conversion ([conv.lval](4.1)), even though it converts an array lvalue to a pointer rvalue -- it's an array-to-pointer conversion ([conv.array](4.2)).

Second use of A::a:

int b  [A::a[1]];

This is no different from the first case, according to the standard. Again, A::a[1] is a constant expression, thus this is a valid array bound, but a compiler is still permitted to emit code at runtime to compute this value, and the array bound still odr-uses A::a.

Note in particular that constant expressions are (by default) potentially-evaluated expressions. Per [basic.def.odr](3.2)/2:

An expression is potentially evaluated unless it is an unevaluated operand (Clause 5) or a subexpression thereof.

[expr](5)/8 just redirects us to other subclauses:

In some contexts, unevaluated operands appear (5.2.8, 5.3.3, 5.3.7, 7.1.6.2). An unevaluated operand is not evaluated.

These subclauses say that (respectively) the operand of some typeid expressions, the operand of sizeof, the operand of noexcept, and the operand of decltype are unevaluated operands. There are no other kinds of unevaluated operand.

这篇关于是一个constexpr数组必须odr使用下标?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆