繁体   English   中英

有没有办法在 C++ 中为基于范围的循环设置偏移量?

[英]Is there a way to set an offset to a range-based for loop in C++?

假设这些类有一个可以通过名为 GetAnotherObjectClassTerms 的函数访问的 AnotherObjectClass 类型的内部数组。

#include<iostream>

int main() {

    // Suppose a default constructor that assigns values to the arrays
    AnObjectClass obj1;
    AnObjectClass obj2;

    for (AnotherObjectClass term1 : obj1.GetAnotherObjectClassTerms) {
        for (AnotherObejctClass term2 : obj2.GetAnotherObjectClassTerms) {
            if (term1 > term2) {
                std::cout << "Term 1 is greater than term 2" << std::endl;
            } else {
                std::cout << "Term 1 is not greater than term 2" << std::endl;
                // OFFSET THIS INNER LOOP so it doesn't iterate through all the items again.
                break;
            }
        }
    }
}

我可以在普通的 for 循环中通过创建一个保存最后一个索引的变量来做到这一点,这样当它开始迭代时,它就会从那个特定位置开始。

以下代码是根据要求使用传统的 for 循环来显示我的问题。

for (unsigned short i = 0, temp = 0; i < 3; i++) {
    for (unsigned short j = temp; j < 3; j++) {
        // This traditional for-loop iterates through a different range
        // whenever the 'temp' value is increased

        if (j > i) {
            std::cout << j << " > " << i << std::endl;
        }
        else {
            std::cout << j << " <= " << i << std::endl;
            temp++;
        }
    }
}

上面代码的输出将是:

Output #1: 0 <= 0

Output #2: 1 > 0

Output #3: 2 > 0

Output #4: 1 <= 1

Output #5: 2 > 1

Output #6: 2 <= 2

如您所见,只要变量 temp 增加,内循环就不会从“开始”开始迭代。

所以我的问题是:这可以在基于范围的 for 循环中完成吗? 如果是这样,如何将此偏移量应用于范围基础 for 循环? 或者,我应该完全避免这种情况并使用正常的 for 循环吗?

我遇到的真正问题是,当到达 break 语句时我需要内部循环以 +1 的偏移量开始

考虑到基于范围的 for 循环遍历数组的元素。

如果您可以使用 Boost,则可以使用boost::adaptors::sliced来获取范围的一部分。 下面是一个完整的例子:

#include <cstddef> // std::size_t
#include <iostream>
#include <iterator>
#include <boost/range/adaptor/sliced.hpp>

int main() {
    int a[] = {0,1,2}, b[] = {0,1,2};

    std::size_t off = 0;
    for (int term1 : a) {
        for (int term2 : b | boost::adaptors::sliced(off, std::size(b))) {
                                                          // ^^^^^^^^^ C++17 feature
            if (term1 > term2) {
                std::cout << "Term 1 is greater than term 2" << std::endl;
            } else {
                std::cout << "Term 1 is not greater than term 2" << std::endl;
                ++off;
                break;
            }
        }
    }
}

输出:

Term 1 is not greater than term 2
Term 1 is not greater than term 2
Term 1 is not greater than term 2

你也可以实现一个简单的类,比如Offset 当与范围结合时,它返回一个代理类,其中包含begin()end()成员函数(以便它能够像范围一样工作),比如说View ,它表示偏移范围。

示例:

#include <cstddef> // std::size_t
#include <iostream>
#include <iterator>
#include <utility>

struct Offset {
    std::size_t _offset;
};

constexpr Offset offset(std::size_t s)
{
    return {s};
}

template <typename Iterator>
struct View {
    constexpr Iterator begin() const {return _begin;}
    constexpr Iterator end() const {return _end;}
    Iterator _begin;
    Iterator _end;
};

// Combine a range with an Offset using operator| like boost::adaptors::sliced
template <typename Range>
auto operator |(Range &&range, const Offset &offset) 
    -> View<decltype(std::begin(std::forward<Range>(range)))> 
{
    return {
        std::begin(std::forward<Range>(range)) + offset._offset, 
        std::end(std::forward<Range>(range))
    };
}

int main() {
    int a[] = {0,1,2}, b[] = {0,1,2};

    std::size_t off = 0;
    for (int term1 : a) {
        for (int term2 : b | offset(off)) {
            if (term1 > term2) {
                std::cout << "Term 1 is greater than term 2" << std::endl;
            } else {
                std::cout << "Term 1 is not greater than term 2" << std::endl;
                ++off;
                break;
            }
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM