考虑以下示例代码(我实际上使用更长的二进制字符串,但这足以解释问题):
void enumerateAllSubsets(unsigned char d) {
unsigned char n = 0;
do {
cout<<binaryPrint(n)<<",";
} while ( n = (n - d) & d );
}
该函数(由于 Knuth)有效地循环遍历二进制字符串的所有子集;
例如:
33 = '00100001' in binary and enumerateAllSubsets(33) would produce:
00000000, 00100000, 00000001, 00100001.
我需要写一个#define,这将使
macroEnumerate(n,33)
cout<<binaryPrint(n)<<",";
其行为方式与 enumerateAllSubsets(33) 等效。 (嗯,顺序可能会重新排列)
基本上我需要能够对集合的子集执行各种操作。
用 for 循环做类似的事情很简单:
for(int i=0;i < a.size();i++)
foo(a[i]);
可以替换为:
#define foreach(index,container) for(int index=0;index < container.size();index++)
...
foreach(i,a)
foo(a[i]);
enumerateAllSubsets() 的问题是循环体需要无条件执行一次,因此 do-while 不能像 for 那样重写。
我知道这个问题可以通过 STL 风格的模板函数和传递给它的 lambda 来解决(类似于 STL for_each 函数),但一些糟糕的 #define 宏似乎是一个更干净的解决方案。
最佳答案
假设使用 C++11,定义一个范围对象:
#include <iostream>
#include <iterator>
#include <cstdlib>
template <typename T>
class Subsets {
public:
Subsets(T d, T n = 0) : d_(d), n_(n) { }
Subsets begin() const { return *this; }
Subsets end() const { return {0, 0}; }
bool operator!=(Subsets const & i) const { return d_ != i.d_ || n_ != i.n_; }
Subsets & operator++() {
if (!(n_ = (n_ - d_) & d_)) d_ = 0;
return *this;
}
T operator*() const { return n_; }
private:
T d_, n_;
};
template <typename T>
inline Subsets<T> make_subsets(T t) { return Subsets<T>(t); }
int main(int /*argc*/, char * argv[]) {
int d = atoi(argv[1]);
for (auto i : make_subsets(d))
std::cout << i << "\n";
}
我已经将其变得非常通用,以防您想要使用,例如 uint64_t
。
关于c++ - 将 do-while 循环压缩为 #define 宏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20823203/