7

您可以在 for 循环中定义 2 个相同类型的变量:

int main() {
  for (int i = 0, j = 0; i < 10; i += 1, j = 2*i) {
    cout << j << endl;
  }
}

但是定义不同类型的变量是违法的:

int main() {
  for (int i = 0, float j = 0.0; i < 10; i += 1, j = 2*i) {
    cout << j << endl;
  }
}

有没有办法做到这一点?(我不需要i在循环内使用,只需j。)

如果你有完全破解和模糊的解决方案,这对我来说没关系。

在这个人为的例子中,我知道你可以只使用double这两个变量。我正在寻找一个普遍的答案。

请不要建议将任何变量移到 for body 之外,这对我来说可能不可用,因为一个迭代器必须在循环之后消失,而 for 语句将包含在我的foreach宏中:

#define foreach(var, iter, instr) {                  \
    typeof(iter) var##IT = iter;                     \
    typeof(iter)::Element var = *var##IT;            \
    for (; var##_iterIT.is_still_ok(); ++var##IT, var = *var#IT) {  \
      instr;                                         \
    }                                                \
  }

它可以这样使用:

foreach(ii, collection, {
  cout << ii;
}). 

但我需要这样使用的东西:

foreach(ii, collection)
  cout << ii;

请不要引入任何运行时开销(但编译可能会很慢)。

4

13 回答 13

27

请不要建议将任何变量移到 for body 之外,因为迭代器必须在循环之后消失,因此可能对我不可用。

你可以这样做:

#include <iostream>

int main( int, char *[] ) {
    {
        float j = 0.0;

        for ( int i = 0; i < 10; i += 1, j = 2*i ) {
            std::cout << j << std::endl;
        }
    }

    float j = 2.0; // works

    std::cout << j << std::endl;

    return 0;
}
于 2009-05-14T21:51:14.130 回答
11

嗯,很丑。但是你可以使用pair。

int main() {
  for (std::pair<int,float> p(0,0.0f); 
       p.first < 10; 
       p.first += 1, p.second = 2*p.first) {
    cout << p.second << endl;
  }
}
于 2009-05-14T21:54:18.397 回答
10

这是一个使用 boost 预处理器的版本(这只是为了好玩。对于现实世界的答案,请参阅上面的@kitchen ):

FOR((int i = 0)(int j = 0.0), i < 10, (i += 1, j = 2 * i)) { 

}

第一部分指定了一系列声明:(a)(b).... 后面声明的变量可以引用前面声明的变量。第二和第三部分和往常一样。在第二部分和第三部分出现逗号的地方,可以使用括号来防止它们分隔宏参数。

我知道有两个技巧用于声明变量,这些变量稍后在添加到宏之外的复合语句中可见。第一个使用条件,例如 if:

if(int k = 0) ; else COMPOUND_STATEMENT

然后k是可见的。自然,它总是必须评估为false。所以它不能被我们使用。另一个上下文是这个:

for(int k = 0; ...; ...) COMPOUND_STATEMENT

这就是我要在这里使用的。我们必须注意只进行一次迭代COMPOUND_STATEMENT。执行增量和条件检查的实际for循环必须在最后,因此附加的复合语句属于它。

#include <boost/preprocessor.hpp>
#include <iostream>

#define EMIT_DEC_(R,D,DEC) \
    for(DEC; !_k; ) 

#define FOR(DECS, COND, INC) \
    if(bool _k = false) ; else \
      BOOST_PP_SEQ_FOR_EACH(EMIT_DEC_, DECS, DECS) \
        for(_k = true; COND; INC)

int main() {
    FOR((int i = 0)(float j = 0.0f), i < 10, (i += 1, j = 2 * i)) {
        std::cout << j << std::endl;
    }
}

它正在创建一堆for语句,每个语句都嵌套在另一个语句中。它扩展为:

if(bool _k = false) ; else
  for(int i = 0; !_k; )
    for(float j = 0.0f; !_k; )
      for(_k = true; i < 10; (i += 1, j = 2 * i)) {
        std::cout << j << std::endl;
      }
于 2009-05-14T22:52:39.427 回答
8
{
  int i = 0;
  float j = 0.0;
  for ( ; i < 10; i += 1, j = 2*i) {
    cout << j << endl;
  }
}

变量在块之后“消失”。

于 2009-05-14T21:52:31.630 回答
7

这将使迭代器(或在本例中为浮点数)在不再需要时消失:

int main() {
  // some code...

  {
    float j = 0.0;
    for (int i = 0; i < 10; i += 1, j = 2*i) {
      cout << j << endl;
    }
  }

  // more code...
}
于 2009-05-14T21:52:33.957 回答
6

如果您在使用宏时遇到问题,有一个标准do..while技巧可以完美运行:

#define MYFOR(init, test, post, body) \
    do \
    { \
        init \
        for( ; test; post) \
            body \
    } while(0)

按如下方式使用它:

MYFOR( int i = 0; float j = 0.0f; , i < 10 , (i += 1, j = 2.0f * i),
    {
         cout << j << endl;
    } );

它很丑,但它可以满足您的要求:iand的范围jdo..while宏循环的限制,并且它需要一个分号结尾,因此您不会因为将它放在 if/else 的谓词中而被咬陈述。

于 2009-05-14T22:20:14.700 回答
5

这也很丑陋,但也提供了一些通用方法来在 for 循环中声明具有某些给定名称和类型的多个变量

int main() {
  for (struct { int i; float j; } x = { };
       x.i < 10; x.i += 1, x.j = 2 * x.i) {
    cout << x.j << endl;
  }
}
于 2009-05-20T16:49:54.117 回答
4

编辑:问题再次改变。现在的问题明确地想要实现一个 foreach 循环。最简单的答案:

#include <boost/foreach.hpp>
void( std::vector<int>& v ) {
   BOOST_FOREACH( int & x, v ) {
      x = x*2;
   }
}

将变量注入代码块

这不是一个答案,而是展示一种更通用的将变量注入代码块的技术。似乎 OP 试图定义的宏可能会使用,即使它确实会产生一些开销

有几个地方可以定义具有不同范围的变量。您可以在任何代码块内定义一个变量,其生命周期将持续到该特定块的末尾。您可以在 for 循环的括号中定义一个变量,范围将是循环块。您还可以在 if 块内定义一个变量,其范围将是 if(包括 else 子句)的范围。

您可以结合上面的这些选项在外部创建变量并将变量注入代码块,而无需创建寿命超过代码块的变量。一个实际的例子是定义一个 foreach 循环(简化为仅适用于 STL 容器。调用语法为:

void f( std::vector<int>& container ) 
{
   INTVECTOR_FOREACH( int & x, container )
   {
      x = x*2;
   }
}

使用类似于其他语言中的 foreach 的语义:x 被引用到容器中的每个元素,因此该函数实际上将整数向量中的每个值加倍。

现在简化宏的代码:

#define INTVECTOR_FOREACH( variable, container ) \
   for ( std::vector<int>::iterator it = container.begin(); it!=container.end(); ++it ) \
      if ( bool condition=false ) {} else \
         for ( variable = *it; !condition; condition=true )

为任何容器和类型概括宏需要一些不属于问题上下文的元编程,但它如何工作的想法(我希望)不应该太难理解。

外部for迭代容器,在每次迭代中,我们只执行一次定义迭代变量(示例代码中的 int & x)。我们需要一个条件来控制内部循环的迭代次数 (1),并且该条件被注入if。我们选择让 if 失败,这样我们就可以确保如果用户在循环之后编写 else 不会得到意外的结果……宏很棘手。

于 2009-05-14T22:51:29.993 回答
3

请不要建议将任何变量移到 for body 之外,因为迭代器必须在循环之后消失,因此可能对我不可用。

您仍然可以这样做,并将整个内容放在花括号中,以使额外的变量超出范围。

int main() 
{
  {
    float j = 0.0;
    for (int i = 0; i < 10; i += 1, j = 2*i) 
    {
      cout << j << endl;
    }
  }
  // more code...
}

这种方式j会在循环之后立即超出范围。

于 2009-05-14T21:54:24.247 回答
2

根据您给出的要求,我能想到的最简单的代码是:

for ( int i = 0; i < 10; ++i )
{
   float f = i * 2;
   std::cout << f << std::endl;
}

您只使用f作为i值的两倍。生命周期仅限于循环,并且(至少在您提供的简化问题中)浮动的创建成本很低(与分配一样便宜)。

如果构造真正的浮点数(我假设因为 i 不是真正的 int,f 也可能不是浮点数)比重新分配值要昂贵得多,那么封装在一对额外的花括号内的其他解决方案限制范围将是最好的选择。

于 2009-05-14T22:02:22.420 回答
1
int main() {
  for (int i = 0, float j = 0.0; i < 10; i += 1, j = 2*i) {
    cout << j << endl;
  }
}

也许我很密集,但你为什么还要声明浮动?无论如何,当你离开循环时,你只是“把它扔掉”。对?

for(int i=0; i<10; ++i)
    cout << (float)2*i << endl;

为什么需要j?

于 2009-05-14T22:12:06.827 回答
1

你说 thei是你自己的类型,你只需要生成jout of i,对吧?简单的。将成员函数添加到i的类以生成j值,并始终使用它。如果需要,您甚至可以创建一个宏来“隐藏”对该成员函数的调用。:-)

于 2009-05-14T22:14:35.103 回答
0

为什么不直接在 for 循环之外声明和初始化变量呢?您仍然可以像现在一样测试和增加它。

于 2009-05-14T21:51:38.217 回答