简体   繁体   English

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

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

Suppose that these classes have an inner array of AnotherObjectClass type that can be accessed through a function called GetAnotherObjectClassTerms.假设这些类有一个可以通过名为 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;
            }
        }
    }
}

I can do this in a normal for loop by creating a variable that holds that last index, so that when it starts iterating, it starts from that specific position.我可以在普通的 for 循环中通过创建一个保存最后一个索引的变量来做到这一点,这样当它开始迭代时,它就会从那个特定位置开始。

The following code is to show my problem using a traditional for-loop as requested.以下代码是根据要求使用传统的 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++;
        }
    }
}

The output of the code above would be:上面代码的输出将是:

Output #1: 0 <= 0

Output #2: 1 > 0

Output #3: 2 > 0

Output #4: 1 <= 1

Output #5: 2 > 1

Output #6: 2 <= 2

As you can see, the inner loop doesn't iterate from the "beginning" whenever the variable temp is incremented.如您所见,只要变量 temp 增加,内循环就不会从“开始”开始迭代。

So my question is: can this be done in a range-based for loop?所以我的问题是:这可以在基于范围的 for 循环中完成吗? If so, how this offset can be applied to a range-base for loop?如果是这样,如何将此偏移量应用于范围基础 for 循环? Or, should I completely avoid this and go with a normal for-loop?或者,我应该完全避免这种情况并使用正常的 for 循环吗?

The real problem that I'm having is that I need the inner loop to start by an offset by +1 when the break statements is reached .我遇到的真正问题是,当到达 break 语句时我需要内部循环以 +1 的偏移量开始

Take into account that the range-based for is looping through the elements of an array.考虑到基于范围的 for 循环遍历数组的元素。

If you can use Boost, you can use boost::adaptors::sliced to get a slice of your range.如果您可以使用 Boost,则可以使用boost::adaptors::sliced来获取范围的一部分。 The following is a complete example:下面是一个完整的例子:

#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;
            }
        }
    }
}

Output:输出:

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

You can also implement a simple class, say Offset .你也可以实现一个简单的类,比如Offset When combined with a range, it returns a proxy class with begin() and end() member functions (so that it is able to behave like a range), say View , which represents the offseted range.当与范围结合时,它返回一个代理类,其中包含begin()end()成员函数(以便它能够像范围一样工作),比如说View ,它表示偏移范围。

Example:示例:

#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