为什么必须在基于范围的for循环中使用引用

时间:2015-12-27 04:08:29

标签: c++ arrays loops

我被困在C ++ Primer中的一段代码中并且已经考虑了超过1小时。代码是

for (auto row : ia)//should use &row here
   for (auto col : row)

对它的解释是

  

我们这样做是为了避免正常的数组转换为指针。因为row不是引用,当编译时   初始化row它将转换每个数组元素(就像数组类型的任何其他对象一样)   指向该数组的第一个元素的指针。结果,在这个循环中行的类型是   INT *。内部for循环是非法的。尽管我们的意图,该循环试图   迭代一个int *。

我知道每次执行for(auto col:row)时都会与迭代有关。我无法理解的是什么

  

我们这样做是为了避免正常的数组到指针转换"

是" ia"的形式。我们传入了外循环?它应该是一个指针指向其第一个元素的地址而不是一个"具体的"阵列?那么内循环有什么不对?我认为它应该是与外循环相同的机制..我无法理解Q& A上的帖子。有人请赐教我...我的理解有什么不对......也欢迎一个好的链接!提前谢谢了!

ia的声明是

constexpr size_t rowCnt = 3, colCnt = 4;
int ia[rowCnt][colCnt]; // 12 uninitialized elements
// for each row
  for (size_t i = 0; i != rowCnt; ++i) {
// for each column within the row
    for (size_t j = 0; j != colCnt; ++j) {
// assign the element's positional index as its value
        ia[i][j] = i * colCnt + j;
    }
}

3 个答案:

答案 0 :(得分:5)

通常,基于范围的for循环声明为:

 for ( decl : coll ) {
 statement } 
如果coll提供了begin()和end()成员,则

等效于以下内容:

    for (auto _pos=coll.begin(), _end=coll.end(); _pos!=_end; ++_pos ) 
   {  
      decl = *_pos; 
       statement 
    } 

或者,如果不匹配,则通过使用全局begin()和end()将coll作为参数来实现以下内容:

for (auto _pos=begin(coll), _end=end(coll); _pos!=_end; ++_pos )
 { 
    decl = *_pos; 
    statement 
 } 

现在看一下decl = *_pos;行,这里每次编译器初始化dec时,它会将每个数组元素(与数组类型的任何其他对象一样)转换为指向该数组第一个元素的指针。

在你的情况下,raw的类型将是int *,而next for循环无法工作,因此它变得非法。

答案 1 :(得分:4)

基于范围的for循环基于beginend函数,这些函数不在T*上工作,但可以在T[N]上工作。

实施:

for ( range_declaration : range_expression ) loop_statement

是这样的:

{
    auto && __range = range_expression ; 
    for (auto __begin = begin_expr,
        __end = end_expr; 
        __begin != __end; ++__begin) { 
        range_declaration = *__begin; 
        loop_statement 
    } 
} 

由于在外部for循环中,数组会衰减为带有auto row的指针,因此内部for循环将变为非法。

答案 2 :(得分:2)

Range based for循环适用于array typeuser defined type成员函数beginend

array-to-pointer decay rulearray传递给一个取pointer的函数时,数组会衰减到指针
但是当您使用**reference**模板时,模板类型会被推断为array type

template<typename T>
void foo(T&);

int main() {
    int ia[2][2] = {{0,1}, {2,3}};

    auto row_val = ia[0]; //int*
    auto& row_ref = ia[0]; //int [2]

    foo(row_val); //void foo<int*>(int*&)
    foo(row_ref); //void foo<int [2]>(int (&) [2])      
}

在这里你可以看到(从它创建的错误!!)推导出的row_valrow_ref类型不同的

row_val ==> int*
row_ref ==> int [2]

您必须使用for(auto& row: ia)row现在array type而不是pointer。因此你可以使用内循环for (auto col : row)