如何为C++17设计可嵌套的std::views::join独立替代实现
实现C++17兼容的可嵌套
std::views::join替代版本 针对你的需求,以下是一个完全基于C++17标准、支持嵌套展开、允许元素修改的join_view实现,解决了嵌套调用时的类型错误和段问题。
核心设计思路
- 兼容任意输入范围:无论是容器(如
std::vector)还是视图(如嵌套的join_view),只要元素本身是范围类型即可 - 惰性迭代:和标准库视图保持一致,仅在迭代时才遍历内层范围
- 自动跳过空范围:与
std::views::join行为对齐,外层中的空内层范围会被自动跳过 - 支持元素修改:迭代器返回元素的直接引用,允许原地修改
完整代码实现
#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; }
关键注意事项
- 视图语义:
join_view是视图类型,不持有底层元素的拷贝,需保证底层范围的生命周期长于join_view及其迭代器 - const迭代器:当前实现的
const_iterator为简化版本,如需严格返回const引用,可单独实现const_iterator类并替换对应类型 - 兼容性:完全基于C++17标准特性实现,无需依赖任何第三方库
内容的提问来源于stack exchange,提问作者joscao
相关产品推荐
相关产品推荐

