在基于范围的for循环中使用声明的变量

时间:2017-12-16 20:23:18

标签: c++

在下面的示例中,i具有功能范围。但似乎我不能在第二个for循环中使用i。为什么for (i : v1)不起作用,但for (int i : v1)有效?

#include<iostream>
#include<string>
#include<vector>

int main()
{
    std::vector<int> v1;
    int i;
    while(std::cin>>i)
    {
        v1.push_back(i);
    }

    for(i : v1) //for (int i:v1) works
        std::cout<<i<<"\t";
    cout<<std::endl;
    return 0;
}

4 个答案:

答案 0 :(得分:40)

语法问题是基于范围的for循环需要声明命名变量,即它需要一个类型说明符(例如,参见{{ 3}}):

  

for(range_declaration:range_expression)loop_statement

     

range_declaration - 命名变量的声明,其类型   是由...表示的序列的元素的类型   range_expression或对该类型的引用。经常使用汽车   自动类型扣除的说明符

其实我不知道为什么你的问题被低估了;我觉得你的假设很好;只是C ++语法决定以另一种方式定义它。

答案 1 :(得分:34)

基于范围的Traceback (most recent call last): File "manage.py", line 8, in <module> from django.core.management import execute_from_command_line File "/home/ubuntu/mywasi-root/venv/lib/python3.5/site-packages/django/core/management/__init__.py", line 13, in <module> from django.core.management.base import ( File "/home/ubuntu/mywasi-root/venv/lib/python3.5/site-packages/django/core/management/base.py", line 17, in <module> from django.db.migrations.exceptions import MigrationSchemaMissing File "/home/ubuntu/mywasi-root/venv/lib/python3.5/site-packages/django/db/migrations/__init__.py", line 1, in <module> from .migration import Migration, swappable_dependency # NOQA ImportError: No module named 'django.db.migrations.migration' 专门用于替换类似于以下的循环(这是一种稍微简单的情况;基于范围的for,尤其是C ++ 17版本,更为通用比例子):

for

在大多数情况下,不会使用不同位置的值,而是使用位置本身的元素:

  1. 当改变序列中的元素时,值实际上没有帮助。
  2. 在大多数情况下,复制值非常昂贵,并且保持参考更有效。
  3. 甚至有些情况下无法复制对象。
  4. 因此,基于范围的for (auto it = range.begin(), end = range.end(); it != end; ++it) { use(*it); } 的设计者决定绝对必须支持引用。同时,它旨在对基于范围的for使用相当简单的重写规则。标准中编纂的规则是:

    for

    相当于

    for (<range-decl>: <range>) { <body> }
    

    特别是,暗示{ auto&& range = <range>; // keep the range alive! auto it = begin(range); // actually, reality is bit more complicated auto end = end(range); // actually, reality is a bit more complicated for (; it != end; ++it) { <range-decl> = *it; // this is the rewrite causing your issue <body> } } 声明,而不仅仅是命名变量。此要求的原因通常是<range-decl>前面使用的实体是参考。但是,引用不能反弹。但是,在循环的每次迭代中,都可以使用新的引用。

    原则上,如果:不是声明而是左值,则重写规则可以使用赋值。这会产生一些奇怪的行为:

    • <range-decl>for (T const& x: range)之间会有所不同:前者有效,而后者有误。
    • 如果左值是对位于某处(T const& x = 0; for (x: range))的对象的引用,则循环会自动将范围中的所有值分配给位于某处的对象。通常,对象位于堆栈或源范围内(当变量被声明为引用时)。

    根据变量的声明方式,仅允许初始化比支持初始化或赋值更合理。查看提案的修订历史(N2930和前任)不会产生讨论,但我含糊地回忆起这一点已被讨论过。

答案 2 :(得分:1)

当您使用基于范围的循环时,在打开括号后需要声明,而不仅仅是变量。正确的语法是:

 for ( declaration : range ) statement;

您可以查看this link了解详情。

在您的示例中:当您在i循环之前声明while时,您可以在所有main函数及其范围内使用它是main函数。您可以在for正文中使用它。当您在i范围内使用for变量时,您没有声明它,因为您已经在上面声明了它,因此它会给您一个错误,并且它对C ++语法不正确。< / p>

但是当您在int括号中的i之前键入for时,您要声明另一个名为i的变量,但仅针对您的{{1}循环,然后使用C ++语法就可以了。

答案 3 :(得分:0)

基本原理很可能是因为这会对变量调用复制分配,这会成为效率低下的潜在根源,而且在实践中几乎从不是意图...如果类型支持完全复制。
所以他们可能认为最好禁止这个。