基于范围隐式添加`const`限定符?

nbu*_*bis 13 c++ const initializer-list c++11

让我们看一下基于循环的以下简单范围:

  int a = 5, b = 6;
  for (auto & i : {a, b})
  {
      std::cout << i << std::endl; // Works as expected.
      i = 3;                       // Error!
  }
Run Code Online (Sandbox Code Playgroud)

gcc抱怨assignment of read-only reference 'i',暗示与初始化列表一起使用的基于for循环的范围隐式const地为引用添加了一个限定符,完全没有说明.

  1. 为什么会这样?
  2. 是否有解决方案允许修改基于循环的范围内的变量?

Sho*_*hoe 22

int a = 5, b = 6;
for (auto & i : {a, b})
Run Code Online (Sandbox Code Playgroud)

您有{a, b}std::initialiser_list两个要素,a并且b,其中的价值ab被复制.现在,std::initializer_list 只为它的元素提供常量迭代器,因为initializer_lists是不可变的,所以你不能将值绑定到非const左值引用.

一种选择是传递指针,这将使指针本身保持不变,但不是它们指向的值:

for (auto& i : {&a, &b}) 
    *i = 0;
Run Code Online (Sandbox Code Playgroud)

Live demo

另一种选择是使用a std::reference_wrapper,但在这种情况下仍需要调用.get()或显式转换static_cast<int&>:

for (auto& i : {std::ref(a), std::ref(b)}) 
    i.get() = 0;
Run Code Online (Sandbox Code Playgroud)

Live demo

考虑到std::reference_wrapper 有一个隐式转换运算符T&,如果在其他一些上下文中你能够自动触发隐式转换(而不是调用.get()),我不会感到惊讶.


另外请注意,{a, b}不是从一系列的数字ab,它真的只是这两个数字.所以,int a = 0, b = 10你不会有,[0, 10]0后面的列表10.

如果你想拥有"适当"的范围,我建议你看看Boost.Range.


Tar*_*ama 9

这与基于范围的循环无关.问题std::initializer_list<int>::iteratorconst int*.你不能改变一个的内容initializer_list.如果您要使用类似的类型std::vector<int>,这将工作正常.