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

发布于 2024-07-19 13:42:38 字数 1191 浏览 13 评论 0原文

你可以在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 主体之外,可能对我来说不可用,因为它是一个迭代器,必须在循环之后立即消失,并且 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;

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

You can define 2 variables of the same type in a for loop:

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

But it is illegal to define variables of different types:

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

Is there a way to do this? (I don't need to use i inside the loop, just j.)

If you have totally hacked and obscure solution, It's OK for me.

In this contrived example I know you could just use double for both variables. I'm looking for a general answer.

Please do not suggest to move any of the variables outside of for body, probably not usable for me as one is an iterator that has to disappear just after the loop and the for statement is to be enclosed in my foreach macro:

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

It can be used thus:

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

But I need something that will be used like that:

foreach(ii, collection)
  cout << ii;

Please do not introduce any runtime overhead (but it might be slow to compile).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

人心善变 2024-07-26 13:42:38

这是一个使用 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

Then k 可见。 当然,它总是必须评估为false。 所以我们不能使用它。 另一种上下文是这样的:

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

这就是我要在这里使用的。 我们必须注意仅对 COMPOUND_STATMENT 进行一次迭代。 执行增量和条件检查的实际 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;
      }

Here is a version using boost preprocessor (This is just for fun. For the real-world answer, see @kitchen's one above):

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

}

The first part specifies a sequence of declarations: (a)(b).... The variables declared later can refer to variables declared before them. The second and third part are as usual. Where commas occur in the second and third parts, parentheses can be used to prevent them to separate macro arguments.

There are two tricks known to me used to declare variables that are later visible in a compound statement added outside a macro. The first uses conditions, like an if:

if(int k = 0) ; else COMPOUND_STATEMENT

Then k is visible. Naturally, it always have to evaluate to false. So it can't be used by us. The other context is this one:

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

That's what i'm going to use here. We'll have to watch to only make one iteration of COMPOUND_STATEMENT. The actual for loop that does the increment and condition checking has to come at the end, so the appended compound statement appertains to it.

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

It's creating a bunch of for statements, each nested into another one. It expands into:

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;
      }
神妖 2024-07-26 13:42:38

嗯,这很丑。 但你可以使用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;
  }
}

Well, it's ugly. But you could use 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;
  }
}
混浊又暗下来 2024-07-26 13:42:38

请不要建议移动任何
for 主体之外的变量,
可能对我来说不可用,因为
迭代器必须立即消失
循环。

你可以这样做:

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

Please do not suggest to move any of
the variables outside of for body,
probably not usable for me as the
iterator has to disappear just after
the loop.

You could do this:

#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;
}
缺⑴份安定 2024-07-26 13:42:38
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?

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

Maybe I'm being dense, but why do you even have to declare the float? You just "throw it away" when you leave the loop anyways. Right?

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

Why do you need j?

酷炫老祖宗 2024-07-26 13:42:38

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

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

您仅使用 f 作为 i 值的两倍。 生命周期仅限于循环,并且(至少在您提供的简化问题中)浮点数的创建成本低廉(与分配成本完全相同)。

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

With the requirements you give the simplest code I can think of is:

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

You only use f as twice the value of i. The lifetime is limited to the loop and (at least in the simplified question you provide) floats are cheap to create (exactly as cheap as to assign).

If construction of the real float (I am assuming that since i is not really an int, f may not be a float either) is much more expensive than reassigning the value, then the other solutions of encapsulating inside an extra pair of curly braces to limit scope would be the best option.

箜明 2024-07-26 13:42:38

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

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

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

这样 j 将在循环之后立即超出范围。

Please do not suggest to move any of the variables outside of for body, probably not usable for me as the iterator has to disappear just after the loop.

You could still do that, and put the whole thing in curly braces to make the extra variable go out of scope.

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

This way j would go out of scope right after the loop.

離殇 2024-07-26 13:42:38

这也很丑陋,但也提供了一些通用方法,用于在 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;
  }
}

This one is also ugly, but provides also some general way for declaring multiple variables with some given name and types in a 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;
  }
}
只怪假的太真实 2024-07-26 13:42:38

编辑:问题再次改变。 现在的问题明确想要实现一个 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 )的 for 我们需要一个条件来控制内部循环的迭代次数 (1),并且该条件是用 if 注入的,我们选择使 if 失败,以便我们可以确保用户这样做。如果她在循环后编写 else,则不会得到意外的结果...宏很棘手。

EDIT: Question has changed once more. The question now explicitly wants to implement a foreach loop. The simplest answer:

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

Injecting a variable into a code block

This is not intended as an answer, but to show a more general technique for injecting a variable into a code block. It seems as if the macro the OP is trying to define might use, even if it does incur in some overhead

There are a couple of places where you can define a variable with different scopes. You can define a variable inside any code block, and its lifespan will be to the end of that particular block. You can define a variable in the parenthesis of a for loop and the scope will be the loop block. You can also define a variable inside an if block and its scope will be that of the if (including the else clause).

You can combine those options above to create externally and inject variables into a code block without creating a variable whose lifespan exceeds that of the block. A practical example would be defining a foreach loop (simplified to work only on STL containers. The calling syntax would be:

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

With semantics similar to foreach in other languages: x gets referenced to each element in the container, so that the function actually doubles each value inside the integer vector.

Now the code of the simplified macro:

#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 )

Generalizing the macro for any container and type requires some metaprogramming that falls out of the context of the question, but the idea of how it works (I hope) should not be too hard to follow.

The external for iterates over the container, in each iteration we execute another for only once defining the iterating variable (int & x in the sample code). We need a condition to control the number of iterations (1) of the internal loop, and that condition is injected with an if. We choose to make the if fail so that we can ensure that the user does not get unexpected results if she writes an else after the loop... macros are tricky.

晌融 2024-07-26 13:42:38

如果您在使用宏时遇到问题,有一个标准的 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;
    } );

它很丑陋,但它可以满足您的要求:i 的范围j 受到宏中的 do..while 循环的限制,并且它需要在末尾有一个分号,所以你不会被将其放在 if/else 语句的谓词中。

If you're having trouble with macros, there's a standard do..while trick that works perfectly:

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

Use it as follows:

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

It's ugly, but it does what you want: the scope of i and j is limited by the do..while loop from the macro, and it requires a semicolon at the end, so you won't get bitten by putting it in the predicate of an if/else statement.

烟燃烟灭 2024-07-26 13:42:38
{
  int i = 0;
  float j = 0.0;
  for ( ; i < 10; i += 1, j = 2*i) {
    cout << j << endl;
  }
}

变量在块之后“消失”。

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

The variables "disappear" after the block.

泪之魂 2024-07-26 13:42:38

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

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

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

  // more code...
}

This will make the iterator (or in this case, float) disappear when it's no more needed:

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

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

  // more code...
}
梦亿 2024-07-26 13:42:38

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

Why don't you just declare and initialize your variables outside of the for loop? You can still test and increment as you have it now.

执笏见 2024-07-26 13:42:38

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

You say the i is your own type, and you just need to generate j out of i, right? Easy. Add a member function to i's class to generate the j value, and use that always. You can probably even make a macro to "hide" the call to that member function, if you want. :-)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文