有没有办法在for循环初始化器中定义两种不同类型的变量?

时间:2009-05-14 21:47:46

标签: c++ for-loop scope initializer variable-declaration

您可以在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。我正在寻找一般答案。

请不要建议移动body之外的任何变量,可能对我不可用,因为一个迭代器必须在循环之后消失并且for语句将包含在我的{{1}中}宏:

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;
}). 

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

13 个答案:

答案 0 :(得分:25)

  

请不要建议移动任何一个   身体外的变量,   可能不适合我   迭代器必须在之后消失   循环。

你可以这样做:

#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;
}

答案 1 :(得分: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;
  }
}

答案 2 :(得分: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;
      }

答案 3 :(得分:8)

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

块后的变量“消失”。

答案 4 :(得分:7)

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

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

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

  // more code...
}

答案 5 :(得分: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;
    } );

这很丑陋,但它可以做你想要的:ij的范围受到来自宏的do..while循环的限制,并且它最后需要一个分号,所以你不会把它放在if / else语句的谓词中。

答案 6 :(得分:5)

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

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

答案 7 :(得分: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 遍历容器,在每次迭代中,我们只执行另一个 for 一次定义迭代变量(示例代码中的int&amp; x)。我们需要一个条件来控制内部循环的迭代次数(1),并且使用 if 注入该条件。我们选择使if失败,以便我们可以确保用户在循环后写一个else时不会得到意外的结果......宏很棘手。

答案 8 :(得分:3)

  

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

你仍然可以这样做,并将整个事情放在大括号中,以使额外的变量超出范围。

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

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

答案 9 :(得分:2)

根据要求,您可以想到最简单的代码:

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

您只能将 f 用作 i 值的两倍。生命周期仅限于循环(至少在你提供的简化问题中)浮点数很便宜(完全和分配一样便宜)。

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

答案 10 :(得分: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?

答案 11 :(得分:1)

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

答案 12 :(得分:0)

为什么不在for循环之外声明和初始化变量?你现在仍然可以测试和增加它。