什么时候是在C ++ 14中使用的变量odr? [英] When is a variable odr-used in C++14?

查看:264
本文介绍了什么时候是在C ++ 14中使用的变量odr?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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 only e.
  • 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 of e.

[ Example: In the following example, the set of potential results of the initializer of n contains the first S::x subexpression, but not the second S::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 expression ex is odr-used by ex unless applying the lvalue-to-rvalue conversion (4.1) to x yields a constant expression (5.19) that does not invoke any nontrivial 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).

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 form E1[E2], the set contains the potential results of E1.

这篇关于什么时候是在C ++ 14中使用的变量odr?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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