【问题标题】:Is there a way to set an offset to a range-based for loop in C++?有没有办法在 C++ 中为基于范围的 for 循环设置偏移量?
【发布时间】:2018-08-18 23:25:55
【问题描述】:

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

#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 &lt;= 0

Output #2: 1 &gt; 0

Output #3: 2 &gt; 0

Output #4: 1 &lt;= 1

Output #5: 2 &gt; 1

Output #6: 2 &lt;= 2

如您所见,每当变量 temp 递增时,内部循环都不会从“开始”迭代。

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

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

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

【问题讨论】:

  • 在 C++17 中,有一个结构化的绑定声明。在 C++17 之前,您可以提供一个帮助类,它包装您的类的一个实例并提供其自己定制的 begin()end() 和其他按您需要的行为的成员函数 - 用于您需要的一次性情况要在范围的一部分上进行操作,使用“正常”的 for 循环可能更容易。
  • 您的问题是,但我不知道您的代码应该做什么。该评论所在的位置没有合理的内部循环。 Snd 我无法解析您问题中的斜体文本。无论如何,您似乎需要gsl::span 之类的东西。
  • @peter 结构化绑定在这里有何帮助?
  • @Yakk 我的代码应该循环遍历用户定义对象类型的数组。就我而言,我有两个带有这些内部数组的对象。如果您想对我正在编码的内容进行更具体的解释,则对象实际上是多项式,而数组由多项式的项组成。我需要对这两个多项式求和,但你不能对具有不同度数的多项式中的项求和。我正在做的代码使用这个基于范围的连接循环来迭代多项式(存储在数组中)的项,以便正确地对它们求和。
  • @Peter 我从来没有听说过,我要去搜索一下。你将如何实现它?

标签: c++ for-loop foreach


【解决方案1】:

如果您可以使用 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;
            }
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-04
    • 2016-12-01
    • 2023-03-28
    • 2015-04-26
    • 2015-08-27
    • 2011-06-23
    相关资源
    最近更新 更多