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

如何为C++17设计可嵌套的std::views::join独立替代实现

实现C++17兼容的可嵌套std::views::join替代版本

针对你的需求,以下是一个完全基于C++17标准、支持嵌套展开、允许元素修改的join_view实现,解决了嵌套调用时的类型错误和段问题。

核心设计思路

  1. 兼容任意输入范围:无论是容器(如std::vector)还是视图(如嵌套的join_view),只要元素本身是范围类型即可
  2. 惰性迭代:和标准库视图保持一致,仅在迭代时才遍历内层范围
  3. 自动跳过空范围:与std::views::join行为对齐,外层中的空内层范围会被自动跳过
  4. 支持元素修改:迭代器返回元素的直接引用,允许原地修改

完整代码实现

#include <iterator>
#include <type_traits>
#include <utility>

// 类型特征:判断是否为范围(存在begin/end方法)
template <typename T, typename = void>
struct is_range : std::false_type {};

template <typename T>
struct is_range<T, std::void_t<decltype(std::begin(std::declval<T>())), decltype(std::end(std::declval<T>()))>> : std::true_type {};

template <typename T>
constexpr bool is_range_v = is_range<T>::value;

// 类型特征:判断是否为输入范围(迭代器满足输入迭代器要求)
template <typename T, typename = void>
struct is_input_range : std::false_type {};

template <typename T>
struct is_input_range<T, std::void_t<decltype(std::begin(std::declval<T>())), decltype(std::end(std::declval<T>())),
    std::enable_if_t<std::is_base_of_v<std::input_iterator_tag, typename std::iterator_traits<decltype(std::begin(std::declval<T>()))>::iterator_category>>>> : std::true_type {};

template <typename T>
constexpr bool is_input_range_v = is_input_range<T>::value;

// 获取范围的元素引用类型
template <typename R>
using range_reference_t = decltype(*std::begin(std::declval<R&>()));

// 获取范围的元素值类型
template <typename R>
using range_value_t = typename std::iterator_traits<decltype(std::begin(std::declval<R&>()))>::value_type;

template <typename Range>
class join_view {
public:
    static_assert(is_input_range_v<Range>, "输入必须是一个输入范围");
    using outer_range_type = std::decay_t<Range>;
    using inner_range_reference = range_reference_t<outer_range_type>;
    static_assert(is_range_v<std::remove_reference_t<inner_range_reference>>, "输入范围的元素必须也是范围类型");
    
    using inner_range_type = std::remove_reference_t<inner_range_reference>;
    using value_type = range_value_t<inner_range_type>;
    using reference = range_reference_t<inner_range_type>;
    using pointer = typename std::iterator_traits<decltype(std::begin(std::declval<inner_range_type>()))>::pointer;
    using difference_type = std::ptrdiff_t;

    // 完美转发构造函数
    template <typename R>
    explicit join_view(R&& r) : outer_range_(std::forward<R>(r)) {}

    // 迭代器实现
    class iterator {
    public:
        using outer_iterator = decltype(std::begin(std::declval<outer_range_type&>()));
        using inner_iterator = decltype(std::begin(std::declval<inner_range_type&>()));

        iterator() = default;
        iterator(outer_iterator outer_it, outer_range_type& outer_range, inner_iterator inner_it = {})
            : outer_it_(std::move(outer_it)), outer_range_(&outer_range), inner_it_(std::move(inner_it)) {
            if (outer_it_ != std::end(*outer_range_) && inner_it_ == inner_iterator{}) {
                skip_empty_inner_ranges();
            }
        }

        reference operator*() const { return *inner_it_; }
        pointer operator->() const { return std::addressof(*inner_it_); }

        // 前置递增
        iterator& operator++() {
            ++inner_it_;
            if (inner_it_ == std::end(get_current_inner_range())) {
                ++outer_it_;
                skip_empty_inner_ranges();
            }
            return *this;
        }

        // 后置递增
        iterator operator++(int) {
            auto tmp = *this;
            ++*this;
            return tmp;
        }

        friend bool operator==(const iterator& lhs, const iterator& rhs) {
            if (lhs.outer_it_ != rhs.outer_it_) return false;
            if (lhs.outer_it_ == std::end(*lhs.outer_range_)) return true;
            return lhs.inner_it_ == rhs.inner_it_;
        }

        friend bool operator!=(const iterator& lhs, const iterator& rhs) {
            return !(lhs == rhs);
        }

    private:
        outer_iterator outer_it_;
        outer_range_type* outer_range_ = nullptr;
        inner_iterator inner_it_;

        inner_range_reference get_current_inner_range() const {
            return *outer_it_;
        }

        // 跳过所有空的内层范围
        void skip_empty_inner_ranges() {
            while (outer_it_ != std::end(*outer_range_)) {
                auto& inner_range = get_current_inner_range();
                auto inner_begin = std::begin(inner_range);
                if (inner_begin != std::end(inner_range)) {
                    inner_it_ = inner_begin;
                    return;
                }
                ++outer_it_;
            }
            inner_it_ = inner_iterator{};
        }
    };

    iterator begin() { return iterator(std::begin(outer_range_), outer_range_); }
    iterator end() { return iterator(std::end(outer_range_), outer_range_); }

    // const迭代器简化实现(如需严格const语义可单独实现)
    using const_iterator = iterator;
    const_iterator begin() const { return const_iterator(std::begin(outer_range_), const_cast<outer_range_type&>(outer_range_)); }
    const_iterator end() const { return const_iterator(std::end(outer_range_), const_cast<outer_range_type&>(outer_range_)); }

private:
    outer_range_type outer_range_;
};

// 辅助构造函数,简化调用
template <typename Range>
auto join(Range&& r) {
    return join_view<std::decay_t<Range>>(std::forward<Range>(r));
}

测试用例

#include <vector>
#include <iostream>

int main() {
    // 单层展开测试(支持元素修改)
    std::vector<std::vector<int>> single_layer = {{1,2}, {}, {3,4,5}};
    auto joined_single = join(single_layer);
    for (int& val : joined_single) {
        val += 10;
        std::cout << val << " ";
    }
    std::cout << "\n"; // 输出:11 12 13 14 15

    // 嵌套展开测试
    std::vector<std::vector<std::vector<int>>> nested_layer = {{{1,2}, {3}}, {}, {{4,5}}};
    auto joined_nested = join(join(nested_layer));
    for (int val : joined_nested) {
        std::cout << val << " ";
    }
    std::cout << "\n"; // 输出:1 2 3 4 5

    return 0;
}

关键注意事项

  1. 视图语义:join_view是视图类型,不持有底层元素的拷贝,需保证底层范围的生命周期长于join_view及其迭代器
  2. const迭代器:当前实现的const_iterator为简化版本,如需严格返回const引用,可单独实现const_iterator类并替换对应类型
  3. 兼容性:完全基于C++17标准特性实现,无需依赖任何第三方库

内容的提问来源于stack exchange,提问作者joscao

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 09:30:58