使用预处理器重新定义 for 循环

Posted

技术标签:

【中文标题】使用预处理器重新定义 for 循环【英文标题】:Redefining for loops with the preprocessor 【发布时间】:2012-03-06 16:47:43 【问题描述】:

我想做一些有点邪恶的事情。我想重新定义 for 循环来修改条件。有没有办法做到这一点?

根据 GCC 文档,支持重新定义关键字:http://gcc.gnu.org/onlinedocs/cpp/Macros.html

我想做的是为 C++ 做一个“概率”包装器,看看我是否可以用它做任何有趣的事情。

#include <iostream>
#include <cstdlib>

#define P 0.85

#define RANDOM_FLOAT  ((float)rand()/(float)RAND_MAX)

#define RANDOM_CHANCE (RANDOM_FLOAT < P)

#define if(a) if((a) && RANDOM_CHANCE)

#define while(a) while((a) && RANDOM_CHANCE)


// No more for loops or do-while loops
#define do
#define goto

// Doesn't work :(
//#define for(a) for(a) if(!RANDOM_CHANCE)  break;  


int main() 
    srand(time(NULL));

    //Should output a random list of Y's and N's
    for(int i=0; i < 100; ++i) 
        if(i < 100) 
            std::cout << "Y";
         else 
            std::cout << "N";
        
    

    std::cout << std::endl;

    // Will loop for a while then terminate
    int j = 0;
    while(j < 100) 
        ++j;
        std::cout << j << "\n";
    

   std::cout << std::endl;

   return 0;

也许更合理的用途是计算正在运行的程序中的循环迭代次数,例如通过映射

for(int i=0; i < 10; ++i)

for(int i=0; i < 10; ++i, ++global_counter)

有可能完成我想做的事情吗?


编辑:感谢您的回复 - 我真的很感激!

我可以用这个做的一件事是模拟一个公平的硬币(有效地强制 P 为 0.5),注意如果你有一个有偏见的硬币,Pr(HT) == Pr(TH)。我没有发现这个技巧,但它很有用。这意味着您可以近似 P 的任何概率分布。

bool coin() 
  bool c1 = false;
  bool c2 = false;

  if(true) 
    c1 = true;
  
  if(true) 
    c2 = true;
  

  //If they have different faces.
  bool valid = (c1 && !c2) || (!c1 && c2);
  bool result = c1;

  if(valid)  return result; 

  return coin();

【问题讨论】:

这太棒了...在很多不同的级别上... 如果其他人可能需要维护您的代码,请确保他们不知道您住在哪里。 我保证这不会在生产中结束。大概吧。 【参考方案1】:

您是否尝试将else 添加到您的for 循环中?那应该可以正常工作。

#define for(a) for(a) if(!RANDOM_CHANCE)  break;  else

for (int i = 0; i < 10; ++i)

    // do something


/* should roughly compile to:
for (int i = 0; i < 10; ++i) if(!RANDOM_CHANCE)  break;  else

    // do something


or (differing only in whitespace):

for (int i = 0; i < 10; ++i)
    if(!RANDOM_CHANCE)
    
        break;
    
    else
    
        // do something
    
*/

【讨论】:

+1 我正要点击 Post 按钮,答案完全相同。【参考方案2】:

你已经展示过了。这是一个可编译的示例:

#include <iostream>

unsigned globalCounter = 0;

#define for(x)  for(x, ++globalCounter)

int main () 
    for (int i=0; i<10; ++i);
    for (int i=0; i<10; ++i);

    std::cout << globalCounter << '\n';

这会输出 20。但是,现有代码如

for (int i=0; i<x; ++i, foobar+=20)

将中断,因为它现在将两个参数传递给 for 宏。

您需要的是宏重载或可变参数宏。后者在 C99 和 C++11 中得到支持,所以如果你想让邪恶发生:

unsigned globalCounter = 0;
#define for(...)  for(__VA_ARGS__, ++globalCounter)

#include <iostream>

void main () 
    int another = 0;
    for (int i=0; i<10; ++i, ++another);
    for (int i=0; i<10; ++i, ++another);

    std::cout << globalCounter << ' ' << another << '\n';

然后

g++ --std=c++0x source.cc
./a.out
20 20

我不支持这个。宏可能会伤害您的孩子。

【讨论】:

让它可变,最后一个 sn-p 不会破坏它。 #define for(...) for(__VA_ARGS__, ++globalCounter)。 (C++11)。 @R。 Martinho Fernandes:但据我所知,C++ 没有可变参数宏,这就是我添加 C99 答案的原因。 就像我提到的,可变参数宏是在 C++11 中添加的。 @R.MartinhoFernandes:在 n3242 中找不到,通过。 @R.MartinhoFernandes:哦,不知道这个。 Reference,谢谢指点。【参考方案3】:

它不起作用,因为该块不再属于for 语句。转变为

for (int i=0; i < 100; ++i)

   if (!RANDOM_CHANCE)
   
      break;
   


// unrelated to the 'for' above.

    if(i < 100) 
        std::cout << "Y";
     else 
        std::cout << "N";
    

相反,你可以写

#define for(...) for(__VA_ARGS__) if(RANDOM_CHANCE)

所以代码变成了

for (int i=0; i < 100; ++i)
    if (RANDOM_CHANCE)
    
        if(i < 100) 
            std::cout << "Y";
         else 
            std::cout << "N";
        
    

(注意我用的是variadic macros。)


而对于 global_counter 的事情,如果你能保证增量部分永远不会为空,那就简单了:

#define for(...) for(__VA_ARGS__, ++ global_counter)

否则(例如代码中有for(;;)),我认为这是不可能的。

【讨论】:

我认为您可以通过在宏中添加else 来解决第一个问题(请参阅我的答案)。

以上是关于使用预处理器重新定义 for 循环的主要内容,如果未能解决你的问题,请参考以下文章

四:迭代器生成器

前端—— JavaScript基础操作:if语句for循环while循环for...infor...of异常处理函数事件JS选择器JS操作页面样式

for循环的本质

Iterator 和 for...of 循环

15.Iterator和for...of循环

迭代器