简体   繁体   English

基于范围的 for 在数组 ODR 上循环使用该数组吗?

[英]Does a range based for loop over an array ODR-use the array?

When a range based for loop is used to iterate over an array, without binding a reference to each element, does this constitute an ODR-use of the array?当使用基于范围的 for 循环迭代数组时,不绑定对每个元素的引用,这是否构成数组的 ODR 使用?

Example:例子:

struct foo {
    static constexpr int xs[] = { 1, 2, 3 };
};

int test(void) {
    int sum = 0;
    for (int x : foo::xs) // x is not a reference!
        sum += x;
    return sum;
}

// Definition, if needed
///constexpr foo::xs;

Is the definition of foo::xs necessary? foo::xs的定义是否必要?

While this code, and variations of it, appear to work fine, that doesn't mean the definition is never necessary.虽然这段代码及其变体看起来运行良好,但这并不意味着定义从来没有必要。 Lack of a definition of an ODR-used variable rarely produces a diagnostic, since the variable could be defined in another translation unit.缺少对 ODR 使用的变量的定义很少会产生诊断,因为该变量可以在另一个翻译单元中定义。 A linker error is the usual result, but it's quite possible to not get the error if the compiler is able to optimize away every use, which is what happens to the above code.链接器错误是通常的结果,但如果编译器能够优化每次使用,则很有可能不会出现错误,这就是上面代码所发生的情况。 The compiler effectively reduces test() to return 6;编译器有效地将test()减少为return 6; . .

Binding a reference to an element would be an ODR-use, but that isn't done.绑定对元素的引用将是 ODR 使用,但尚未完成。

I was under impression that subscripting an array was not ODR-use in C++14 or later.我的印象是,在 C++14 或更高版本中,下标数组不是 ODR 使用的。 But the range based for is not exactly subscripting.但是基于 for 的范围并不完全是下标。

In C++17, I believe this example avoids the problem because constexpr class data members are implicitly inline.在 C++17 中,我相信这个例子避免了这个问题,因为 constexpr 类数据成员是隐式内联的。 And thus the declaration in the class also serves to define xs and an additional namespace scope definition isn't needed to satisfy ODR.因此,类中的声明也用于定义xs并且不需要额外的命名空间范围定义来满足 ODR。

Some additional versions of the same question:同一问题的一些其他版本:

What if we use std::array ?如果我们使用std::array怎么办?

constexpr std::array<int, 3> xs = { 1, 2, 3 };

What if we avoid the range based for?如果我们避免基于范围怎么办?

for (int i = 0; i < foo::xs.size(); i++) sum += foo::xs[i];

Is the definition of foo::xs necessary? foo::xs的定义是否必要?

Yes, because as NathanOliver points out in the comments, a reference is implicitly bound to foo::xs by the range-based for loop.是的,因为正如 NathanOliver 在评论中指出的那样,引用通过基于范围的 for 循环隐式绑定到foo::xs When you bind a reference to an object, the object is odr-used.当您将引用绑定到对象时,该对象是 odr-used。 The same would occur if an std::array were used rather than a raw array.如果使用std::array而不是原始数组,也会发生同样的情况。

What if we avoid the range based for?如果我们避免基于范围怎么办?

Well, if you use a raw array and get its size using a technique that doesn't require binding a reference to it, then you can avoid providing a definition:好吧,如果您使用原始数组并使用不需要绑定对它的引用的技术来获取它的大小,那么您可以避免提供定义:

for (int i = 0; i < sizeof(foo::xs)/sizeof(foo::xs[0]); i++) {
    sum += foo::xs[i];
}

In this case, the references inside sizeof are not odr-uses because they are unevaluated, and foo::xs is an element of the set of potential results of foo::xs[i] ;在这种情况下, sizeof内部的引用不是 odr-uses,因为它们没有被评估,而foo::xsfoo::xs[i]的潜在结果集合中的一个元素; this latter expression is of non-class type and immediately undergoes an lvalue-to-rvalue conversion, so it does not odr-use foo::xs .后一个表达式是非类类型,并立即进行左值到右值的转换,因此它不使用foo::xs

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM