MWi*_*Wid 25 c++ one-definition-rule c++14
C++ 14草案(N3936)在§3.2/ 3中陈述:
变量x的名称显示为潜在评估的表达式ex,除非将lvalue-to-rvalue转换(4.1)应用于x,否则将生成不调用任何非平凡函数的常量表达式(5.19),并且如果x是一个对象,ex是表达式e的潜在结果集合的元素,其中左值到右值的转换(4.1)应用于e,或者e是丢弃值表达式(第5节).
这对我没有任何意义:如果表达式e是丢弃值表达式取决于使用的上下文e.表达式语句(第6.2节)中使用的每个表达式都是一个丢弃值表达式.如果左值到右值转换被施加到e还依赖于上下文e中被使用.
而且,表达式在另一个表达式的潜在结果集合中意味着什么.人们需要表达式相等的概念才能确定集合的成员资格.但我们没有参考透明度,所以我看不出如何实现这一点.
为什么从C++ 11改为C++ 14?这怎么解释?就目前而言,它没有意义.
MWi*_*Wid 26
非正式地,变量的使用意味着以下内容:
如果程序中任何位置的任何表达式获取对象的地址或将引用直接绑定到对象,则必须定义此对象.
在最新版本的规范§3.2已经澄清(参见GitHub上的C++ 14草案):
2表达式可能会被评估,除非它是未评估的操作数(第5条)或其子表达式.表达式的潜在结果集
e定义如下:
- 如果
e是id-expression(5.1.1),则该集仅包含e.- 如果
e是类成员访问表达式(5.2.5),则该集合包含对象表达式的潜在结果.- 如果
e是指向成员的表达式(5.5),其第二个操作数是常量表达式,则该集合包含对象表达式的潜在结果.- 如果
e具有形式(e1),则该集合包含e1的潜在结果.- 如果
e是glvalue条件表达式(5.16),则该集合是第二个和第三个操作数的潜在结果集合的并集.- 如果
e是逗号表达式(5.18),则该集合包含右操作数的潜在结果.- 否则,该集合为空.
[注意:这个集合是一个(可能是空的)id表达式集合,每个
e表达式都是或者是子表达式e.[示例:在以下示例中,初始化程序的潜在结果集
n包含第一S::x个子表达式,但不包含第二S::x个子表达式.Run Code Online (Sandbox Code Playgroud)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- 末端示例] - 尾注]
3一种可变
x其名称显示为潜在评估表达ex是ODR使用的由ex除非施加左值到右值转换(4.1),以x产生一个常量表达式(5.19),其不调用任何非平凡函数,如果x是对象,ex是表达式的潜在结果集合的元素e,其中左值到右值转换(4.1)应用于e或者e是丢弃值表达式(第5节).
C++ 11中的§3.2/ 2读取:
除非是未评估的操作数(第5条)或其子表达式,否则可能会对表达式进行求值.名称显示为潜在评估表达式的变量是odr-used,除非它是满足出现在常量表达式(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;
}
Run Code Online (Sandbox Code Playgroud)
由于S::a和S::b是x ? S::a : S::b左值,条件表达式也是左值.这意味着左值到右值的转换不会立即应用于S::a和S::b,而是应用于条件表达式的结果.这意味着通过C++ 11的措辞,这些静态数据成员使用起来并且需要定义.但实际上只使用了这些值,因此不需要定义静态数据成员 - 声明就足够了.C++ 14草案的新措辞解决了这个问题.
不可以.在以下示例中,变量S::a仍然使用了odr:
struct S { static constexpr int a[2] = {0, 1}; };
void f() {
auto x = S::a[0];
}
Run Code Online (Sandbox Code Playgroud)
因此,我提交了一个新问题,将以下项目添加到§3.2/ 2:
- 如果
e是表单的glvalue下标表达式(5.2.1),则E1[E2]该集合包含潜在的结果E1.