You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编写适配C++20 std::ranges的自定义前向迭代器及相关疑问

如何编写适配C20 std::ranges 库的C类?

问题背景

编写带迭代器的外观类时,clang++18编译器提示未满足std::ranges要求,深层错误为:

/usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/ranges:946:30: note: because '__adaptor::__is_range_adaptor_closure_fn(__t, __t)' would be invalid: no matching function for call to '__is_range_adaptor_closure_fn'

疑问解答

1. 为什么Iterator需要支持默认构造?

C++20的std::forward_iterator概念强制要求迭代器可默认构造,这是因为很多range适配器(比如std::views::filter)的内部逻辑依赖于创建临时迭代器实例。你的原实现使用了大对象的const引用,直接默认构造会导致悬空引用,解决方式是将引用替换为指针,这样可以默认构造(初始化为nullptr),后续使用时保证指针指向有效对象即可。

2. 实现std::forward_iterator为何需要difference_type?

std::forward_iterator继承自std::input_iterator概念,而input_iterator要求必须定义difference_type这一关联类型——哪怕你不需要实现operator--或operator-这类双向/随机访问迭代器的操作。对于forward迭代器,直接将difference_type定义为std::ptrdiff_t即可,无需额外实现差值计算逻辑。

修正后的代码

#include <cstddef>
#include <iterator>
#include <unordered_set>
#include <concepts>

using Set = std::unordered_set<std::ptrdiff_t>;

class MyFacadeClass {
private:
  class Iterator {
  public:
    using iterator_category = std::forward_iterator_tag;
    using value_type        = std::ptrdiff_t;
    using difference_type   = std::ptrdiff_t;
    using pointer           = const std::ptrdiff_t*;
    using reference         = const std::ptrdiff_t&;

    // 默认构造函数,满足forward_iterator要求
    Iterator() : pSelf(0), pA(nullptr), pB(nullptr), pIt(), pInB(false) {}

    Iterator(const std::ptrdiff_t self,
             const Set* a,
             const Set* b,
             const Set::const_iterator it,
             const bool inB = false) :
      pSelf(self),
      pA(a),
      pB(b),
      pIt(it),
      pInB(inB) {}

    reference operator*() const { return *pIt; }
    pointer operator->() const { return &*pIt; }

    // 补充==运算符,满足equality_comparable要求
    bool operator==(const Iterator& other) const { return pIt == other.pIt; }
    bool operator!=(const Iterator& other) const { return !(*this == other); }

    // 前置递增
    Iterator& operator++() {
        if (pInB) {
          ++pIt;
          return *this;
        }
        else {
          do {
            ++pIt;
            if (pIt == pA->end()) {
              pIt        = pB->begin();
              pInB = true;
              return *this;
            }
          } while (*pIt == pSelf);
          return *this;
        }
      }

    // 后置递增,满足forward_iterator要求
    Iterator operator++(int) {
        Iterator temp = *this;
        ++*this;
        return temp;
      }

  private:
    const std::ptrdiff_t pSelf;
    const Set* pA;  // 替换引用为指针,支持默认构造
    const Set* pB;
    Set::const_iterator pIt;
    bool pInB;
  };

  static_assert(std::forward_iterator<Iterator>);
  static_assert(std::ranges::input_range<MyFacadeClass>);

public:
  Iterator begin() const { return Iterator(self, &pA, &pB, pA.begin()); }
  Iterator end() const { return Iterator(self, &pA, &pB, pB.end()); }

  // 构造函数,初始化成员
  MyFacadeClass(std::ptrdiff_t self_val, const Set& a, const Set& b)
    : self(self_val), pA(a), pB(b) {}

private:
  const std::ptrdiff_t self;
  const Set& pA;
  const Set& pB;
};

使用示例

现在可以正常使用range适配器:

#include <ranges>
#include <iostream>

int main() {
  Set a{1, 2, 3, 4};
  Set b{3, 4, 5, 6};
  const MyFacadeClass my_class(2, a, b);

  // 使用views::filter过滤成员
  for (const auto& member : my_class | std::views::filter([](auto val) { return val % 2 == 0; })) {
    std::cout << member << " ";
  }
  // 输出:4 4 6
  return 0;
}

内容的提问来源于stack exchange,提问作者user-1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 11:57:17