在数组odr上基于范围的for循环是否使用数组?



如果使用基于范围的for循环遍历数组,而不绑定对每个元素的引用,这是否构成对数组的odr使用?

的例子:

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;

foo::xs的定义是否必要?

虽然这段代码和它的变体看起来工作得很好,但这并不意味着没有必要定义它。缺少odr使用的变量的定义很少产生诊断,因为变量可以在另一个翻译单元中定义。通常的结果是链接器错误,但如果编译器能够优化掉每次使用,则很可能不会得到错误,这就是上面代码所发生的情况。编译器有效地将test()还原为return 6;

将引用绑定到一个元素将是一个odr使用,但没有这样做。

我的印象是,在c++ 14或更高版本中,数组下标不是odr使用的。但是基于for的范围并不完全是下标。

在c++ 17中,我相信这个例子避免了这个问题,因为constexpr类的数据成员是隐式内联的。因此,类中的声明也用于定义xs,并且不需要额外的名称空间作用域定义来满足ODR。

相同问题的一些附加版本:

如果我们使用std::array呢?

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

如果我们避免基于范围的for呢?

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

foo::xs的定义是否必要?

是的,因为正如NathanOliver在评论中指出的那样,引用通过基于范围的for循环隐式地绑定到foo::xs。当您将引用绑定到对象时,该对象是odr使用的。如果使用std::array而不是原始数组,也会发生相同的情况。

如果我们避免基于范围的for呢?

好吧,如果你使用一个原始数组,并使用一种不需要绑定引用的技术来获取它的大小,那么你可以避免提供定义:

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

在这种情况下,sizeof内部的引用不是odr使用,因为它们是未求值的,并且foo::xsfoo::xs[i]的潜在结果集合的一个元素;后一个表达式是非类类型的,并立即进行左值到右值的转换,因此它不需要使用foo::xs

相关内容

  • 没有找到相关文章

最新更新