什么时候是在C ++ 14中使用的变量odr? [英] When is a variable odr-used in C++14?
问题描述
C ++ 14草案(N3936)在§3.2/ 3中规定:
一个变量x, - 评估表达式ex是odr使用,除非对x应用lvalue-to-rvalue转换(4.1)产生不调用任何非平凡函数的常量表达式(5.19),并且如果x是对象,则ex是元素表达式e的潜在结果集合,其中左值到右值转换(4.1)应用于e,或e是丢弃值表达式(条款5)。
这对我没有任何意义:如果表达式 e
是一个舍弃值表达式取决于使用 e
的上下文。在 expression-statement (§6.2)中使用的每个表达式都是一个舍弃值表达式。如果对 e
应用 e
用于。
此外,表达式在另一个表达式的潜在结果集合中意味着什么。需要一个表达式相等的概念,以便能够确定集合的成员资格。但是我们没有引用透明,所以我不能看到这是如何实现的。
为什么这从C ++ 11到C ++ 14?这应该如何解释?
odr使用的目的
非正式地,变量的 odr-use 意味着:
在程序中的任何地方的表达式中使用直接引用的对象的地址或绑定到对象的引用。最新版本
在最新版本的规范§3.2中已经阐明(参见在GitHub上的C ++ 14草案):
2除非是未求值的操作数(条款5)或其子表达式。表达式
e
的潜在结果集合的定义如下:
- 如果
e
是一个id表达式(5.1.1),该集合只包含e
。
- 如果
e
是类成员访问表达式(5.2.5),则该集合包含对象表达式的可能结果。
- 如果
e
是指向成员的表达式(5.5),其第二个操作数是常量表达式,则该集合包含对象表达式的可能结果。 / li>
- 如果
e
的形式为(e1),则该集合包含e1的潜在结果。
- 如果
e
是glvalue条件表达式(5.16),则该集合是第二个和第三个操作数的潜在结果集合的并集。
- 如果
e
是逗号表达式(5.18),则该集合包含正确操作数的可能结果。
[注意:此集合是一个(可能为空)的id表达式集合,它是
e
或e
的子表达式。
[示例:在下面的示例中,
n
的初始化器的潜在结果集包含第一个S :: x
子表达式,而不是第二个S :: x
子表达式。
struct S {static const int x = 0; };
const int& f(const int& r);
int n = b? (1,S :: x)// S :: x is not odr-used here
:f(S :: x); // S :: x在这里是odr,所以
//需要一个定义
< blockquote>
-end example] -end note]
3一个变量 x
名称显示为可能评估的表达式 ex
是odr使用由 ex
(4.1)到 x
产生一个不调用任何非平凡函数的常量表达式(5.19),如果 x
是一个对象, ex
是表达式的可能结果集合的一个元素 e
,其中将左值 - 右值转换(4.1)应用于 e
或者 e
C ++ 11中的情况是什么?
§3.2/ 2在C ++ 11中:
一个表达式可能被评估,除非它是一个未求值的操作数条款5)或其子表达式。其名称显示为可能评估的表达式的变量是odr使用的,除非它是满足出现在常量表达式(5.19)和左值到右值转换(4.1)中的要求的对象立即。
这些字词的问题是 DR 712 。考虑这个例子:
struct S {
static const int a = 1;
static const int b = 2;
};
int f(bool x){
return x? S :: a:S :: b;
}
由于 S :: a
和 S :: b
是lvalue条件表达式 x? S :: a:S :: b
也是一个左值。这表示 S :: a
和 S :: b不会立即应用左值到右值转换
,而是条件表达式的结果。这意味着通过C ++ 11的措辞,这些静态数据成员是odr使用的,并且需要定义。但实际上只使用值,因此定义静态数据成员不是必需的 - 声明就足够了。 C ++ 14草案的新措辞解决了这一问题。
新的措辞是否解决了所有问题?
没有。在下面的示例中,变量 S :: a
仍然使用odr:
struct S {static constexpr int a [2] = {0,1}; };
void f(){
auto x = S :: a [0];
}
因此我提交了一个新的发布向§3.2/ 2中添加以下项目符号:
< blockquote>
- 如果
e
是形式的glvalue下标表达式E1 [E2]
,该集合包含E1
的潜在结果。
The C++14 draft (N3936) states in §3.2/3:
A variable x whose name appears as a potentially-evaluated expression ex is odr-used unless applying the lvalue-to-rvalue conversion (4.1) to x yields a constant expression (5.19) that does not invoke any non-trivial functions and, if x is an object, ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion (4.1) is applied to e, or e is a discarded-value expression (Clause 5).
This doesn't make any sense to me: If an expression e
is a discarded-value expression depends on the context, in which e
is used. Every expression used in an expression-statement (§6.2) is a discarded-value expression. If the lvalue-to-rvalue conversion is applied to e
also depends on the context e
is used in.
Moreover, what does it mean for an expression to be in the set of potential results of another expression. One needs a notion of equality of expressions to be able to determine membership of a set. But we don't have referential transparency, so I cannot see how this could be achieved.
Why was this changed from C++11 to C++14? And how should this be interpreted? As it stands, it doesn't make sense.
The purpose of odr-use
Informally, odr-use of a variable means the following:
If any expression anywhere in the program takes the address of or binds a reference directly to an object, this object must be defined.
Clarification in the latest draft
In the latest version of the spec §3.2 has been clarified (see Draft C++14 on GitHub):
2 An expression is potentially evaluated unless it is an unevaluated operand (Clause 5) or a subexpression thereof. The set of potential results of an expression
e
is defined as follows:
- If
e
is an id-expression (5.1.1), the set contains onlye
.- If
e
is a class member access expression (5.2.5), the set contains the potential results of the object expression.- If
e
is a pointer-to-member expression (5.5) whose second operand is a constant expression, the set contains the potential results of the object expression.- If
e
has the form (e1), the set contains the potential results of e1.- If
e
is a glvalue conditional expression (5.16), the set is the union of the sets of potential results of the second and third operands.- If
e
is a comma expression (5.18), the set contains the potential results of the right operand.- Otherwise, the set is empty.
[ Note: This set is a (possibly-empty) set of id-expressions, each of which is either
e
or a subexpression ofe
.[ Example: In the following example, the set of potential results of the initializer of
n
contains the firstS::x
subexpression, but not the secondS::x
subexpression.
struct S { static const int x = 0; };
const int &f(const int &r);
int n = b ? (1, S::x) // S::x is not odr-used here
: f(S::x); // S::x is odr-used here, so
// a definition is required
—end example ] —end note ]
3 A variable
x
whose name appears as a potentially-evaluated expressionex
is odr-used byex
unless applying the lvalue-to-rvalue conversion (4.1) tox
yields a constant expression (5.19) that does not invoke any nontrivial functions and, ifx
is an object,ex
is an element of the set of potential results of an expressione
, where either the lvalue-to-rvalue conversion (4.1) is applied toe
, ore
is a discarded-value expression (Clause 5).
What was the situation in C++11?
§3.2/2 in C++11 reads:
An expression is potentially evaluated unless it is an unevaluated operand (Clause 5) or a subexpression thereof. A variable whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression (5.19) and the lvalue-to-rvalue conversion (4.1) is immediately applied.
The problem with these wordings was DR 712. Consider this example:
struct S {
static const int a = 1;
static const int b = 2;
};
int f(bool x) {
return x ? S::a : S::b;
}
Since S::a
and S::b
are lvalues the conditional expression x ? S::a : S::b
is also an lvalue. This means that the lvalue-to-rvalue conversion is not immediately applied to S::a
and S::b
, but to the result of the conditional expression. This means that by the wording of C++11, these static data members are odr-used and a definition is required. But actually only the values are used, hence it is not neccessary to define the static data members - a declaration would suffices. The new wording of draft C++14 solves this.
Does the new wording resolve all issues?
No. In the following example the variable S::a
is still odr-used:
struct S { static constexpr int a[2] = {0, 1}; };
void f() {
auto x = S::a[0];
}
Hence I submitted a new issue to add the following bullet to §3.2/2:
- if
e
is a glvalue subscripting expression (5.2.1) of the formE1[E2]
, the set contains the potential results ofE1
.
这篇关于什么时候是在C ++ 14中使用的变量odr?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!