c++ - 将 do-while 循环压缩为 #define 宏

标签 c++ c macros metaprogramming c-preprocessor

考虑以下示例代码(我实际上使用更长的二进制字符串,但这足以解释问题):

  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/

相关文章:

在 Vim 中搜索 "off the record",或者从搜索历史中删除搜索模式?

c++ - 如何从预处理器宏中识别平台/编译器?

c++ - 插入到链表末尾

c++ - 复制省略和异常(exception)

c++ - throw 和 throw 与捕获异常的 arg 有什么区别?

c++ - 根据字符串值分配成员

c - 使用 libcurl 加载 http URL

c - 逆向汇编 x86 的工程片段?

c - 动态分配链表数组

c - 使用 C 宏制作 lisp 求值器