使用预处理器重新定义 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操作页面样式