【问题标题】:Redefining for loops with the preprocessor使用预处理器重新定义 for 循环
【发布时间】: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();
}

【问题讨论】:

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

标签: c++ c-preprocessor


【解决方案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 来解决第一个问题(请参阅我的答案)。
猜你喜欢
  • 2020-08-14
  • 1970-01-01
  • 1970-01-01
  • 2021-12-29
  • 2015-07-27
  • 1970-01-01
  • 2010-11-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多