C++ C++;:如何用单个命令替换复杂的迭代?

C++ C++;:如何用单个命令替换复杂的迭代?,c++,for-loop,iteration,C++,For Loop,Iteration,问题 我有时有复杂的迭代过程,必须在代码中重复多次,但每次迭代执行的表达式在代码的不同位置不同。必须在任何地方重写迭代过程都是丑陋的,而且容易出错。我如何包装这个迭代过程 示例 例如,考虑这个相对复杂的迭代 std::string bitmask(K, 1); // K leading 1's bitmask.resize(N, 0); // N-K trailing 0's // print integers and permute bitmask do { // Loop thro

问题

我有时有复杂的迭代过程,必须在代码中重复多次,但每次迭代执行的表达式在代码的不同位置不同。必须在任何地方重写迭代过程都是丑陋的,而且容易出错。我如何包装这个迭代过程

示例

例如,考虑这个相对复杂的迭代

std::string bitmask(K, 1); // K leading 1's
bitmask.resize(N, 0); // N-K trailing 0's

// print integers and permute bitmask
do {
    // Loop through BIG and SMALL indices
    for (size_t BIGindex = 0; BIGindex < nbBigs; ++BIGindex)
    {
        size_t nbSmalls;
        if (BIGindex == nbBigs)
        {
            nbSmalls = nbSmallsOfLastBig;
        } else
        {
            nbSmalls = nbSmallsStandard;
        }
        for (size_t SMALLindex = 0; SMALLindex < nbSmalls; ++SMALLindex)
        {
            // doStuff with bitmask, BIGindex and SMALLindex
        }        
    }
} while (std::prev_permutation(bitmask.begin(), bitmask.end()));
一个不完全令人满意的解决方案

实现这一点的一种方法是将要完成的内容包装到一个函数中,例如

void doComplexIterationOnFunction(void (*doStuff)(std::string bitmask, size_t BIGindex, size_t SMALLindex))
{
    std::string bitmask(K, 1); // K leading 1's
    bitmask.resize(N, 0); // N-K trailing 0's

    // print integers and permute bitmask
    do {
        // Loop through BIG and SMALL indices
        for (size_t BIGindex = 0; BIGindex < nbBigs; ++BIGindex)
        {
            size_t nbSmalls;
            if (BIGindex == nbBigs)
            {
                nbSmalls = nbSmallsOfLastBig;
            } else
            {
                nbSmalls = nbSmallsStandard;
            }
            for (size_t SMALLindex = 0; SMALLindex < nbSmalls; ++SMALLindex)
            {
                (*doStuff)(bitmask, BIGindex, SMALLindex);
            }        
        }
    } while (std::prev_permutation(bitmask.begin(), bitmask.end()));
}

但是,,它迫使我系统地将我希望在每次迭代中执行的任何代码包装在一个函数中,这有点麻烦,也有点愚蠢,因为有时代码非常短。

您可以将函数设置为模板类型,然后允许您在调用站点传递lambda,而不是使用函数指针。那看起来像

temaplte<typename Function>
void doComplexIterationOnFunction(Function doStuff)
{
    std::string bitmask(K, 1); // K leading 1's
    bitmask.resize(N, 0); // N-K trailing 0's

    // print integers and permute bitmask
    do {
        // Loop through BIG and SMALL indices
        for (size_t BIGindex = 0; BIGindex < nbBigs; ++BIGindex)
        {
            size_t nbSmalls;
            if (BIGindex == nbBigs)
            {
                nbSmalls = nbSmallsOfLastBig;
            } else
            {
                nbSmalls = nbSmallsStandard;
            }
            for (size_t SMALLindex = 0; SMALLindex < nbSmalls; ++SMALLindex)
            {
                std::invoke(doStuff, bitmask, BIGindex, SMALLindex);
            }        
        }
    } while (std::prev_permutation(bitmask.begin(), bitmask.end()));
}

有一个不同的选择:

通过写入一个范围或至少足够一个范围来反转控制:

与将函数指针甚至lambda传递给模板函数相比,调用方具有更大的灵活性和控制能力。

成本是在写范围时让你的大脑陷入困境。

如果你不想定义函数,你可以传递lambda。lambda是正确的答案
doComplexIterationOnFunction(doSpecificStuff);
temaplte<typename Function>
void doComplexIterationOnFunction(Function doStuff)
{
    std::string bitmask(K, 1); // K leading 1's
    bitmask.resize(N, 0); // N-K trailing 0's

    // print integers and permute bitmask
    do {
        // Loop through BIG and SMALL indices
        for (size_t BIGindex = 0; BIGindex < nbBigs; ++BIGindex)
        {
            size_t nbSmalls;
            if (BIGindex == nbBigs)
            {
                nbSmalls = nbSmallsOfLastBig;
            } else
            {
                nbSmalls = nbSmallsStandard;
            }
            for (size_t SMALLindex = 0; SMALLindex < nbSmalls; ++SMALLindex)
            {
                std::invoke(doStuff, bitmask, BIGindex, SMALLindex);
            }        
        }
    } while (std::prev_permutation(bitmask.begin(), bitmask.end()));
}
doComplexIterationOnFunction(doSpecificStuffFunction) // pass function
doComplexIterationOnFunction(doSpecificStuffFuntor) // pass functor
doComplexIterationOnFunction([](auto foo, auto bar, auto baz) { return foo + bar - baz; }) // pass lambda
struct ComplexIterationRange {
    static constexpr auto end() noexcept { struct {} r; return r; }
    static auto begin() {
        struct {
            std::string bitmask;
            std::size_t SMALLindex = 0, BIGindex = 0;
            const auto& operator*() const noexcept { return *this; }
            auto& operator++() noexcept {
                if (++SMALLindex >= nbSmallsStandard) {
                    if (++BIGindex >= nbBigs) {
                        if (!std::prev_permutation(bitmask.begin(), bitmask.end()))
                            return *this;
                        BIGindex = 0;
                    }
                    SMALLindex = 0;
                }
                return *this;
            }
            bool operator!=(decltype(end())) const noexcept {
                return SMALLindex < nbSmallsStandard || BIGindex < nbBigs;
            }
        } r { []{ std::string r(K, 1); r.resize(N, 0); return r; }() };
        return r;
    }
};
for (auto&& x : ComplexIterationRange()) {
    Use x.SMALLindex, x.BIGindex, and x.bitmask here
    ...
}