如何在C++中动态更新过滤后的range?规避高频检查与昂贵方案
解决方案:动态组合C++20 Ranges视图(无容器复制/类型擦除)
针对运行时条件下动态调整Range视图、避免高频条件检查的需求,以下是几种高效且符合要求的实现方式:
一、运行时条件:用模板函数封装分支处理
核心思路是避免试图用单一变量存储不同类型的视图,而是将后续处理逻辑封装为模板函数,在每个条件分支中传入对应视图。这种方式完全无额外开销,且代码清晰:
#include <iostream> #include <ranges> #include <vector> #include <iterator> // 封装通用处理逻辑,支持任意符合Range概念的类型 template <typename Range> void process_range(const Range& range) { std::ranges::copy(range, std::ostream_iterator<int>{std::cout, ", "}); std::cout << '\n'; } int main() { std::vector<int> v = {0, 1, 2, 3, 4, 5, 6}; const bool strategy_check_for_zero = true; // 按条件构建视图并传入处理函数 if (strategy_check_for_zero) { auto filtered = v | std::views::filter([](const auto& val) { return val != 0; }); process_range(filtered); } else { process_range(v); } }
多条件逐步过滤的场景
如果需要逐个应用多个条件(如先过滤再跳过元素),可在分支中链式构建视图后传递给处理函数:
int main() { std::vector<int> v = {0, 1, 2, 3, 4, 5, 6}; const bool check_zero = true; const bool skip_first = true; if (check_zero && skip_first) { auto processed = v | std::views::filter([](auto val) { return val !=0; }) | std::views::drop(1); process_range(processed); } else if (check_zero) { process_range(v | std::views::filter([](auto val) { return val !=0; })); } else if (skip_first) { process_range(v | std::views::drop(1)); } else { process_range(v); } }
二、运行时条件:用std::variant存储不同视图类型
如果必须将视图存储到单一变量中,可使用std::variant(静态类型安全,无堆分配/类型擦除开销)存储所有可能的视图类型,再通过std::visit统一处理:
#include <variant> int main() { std::vector<int> v = {0, 1, 2, 3, 4, 5, 6}; const bool strategy_check_for_zero = true; // 声明variant,包含原容器和过滤视图两种类型 using RangeType = std::variant< decltype(v), decltype(v | std::views::filter(std::declval<decltype([](int){return true;})>())) >; RangeType selected; if (strategy_check_for_zero) { selected = v | std::views::filter([](const auto& val) { return val != 0; }); } else { selected = v; } // 用std::visit处理variant中的任意类型 std::visit([](const auto& range) { process_range(range); }, selected); }
三、处理“过滤后为空则取消过滤”的场景
先创建过滤视图,检查是否为空后,选择传入原容器或过滤视图到处理函数:
int main() { std::vector<int> v = {0, 0, 0}; // 过滤后为空的测试用例 const bool strategy_check_for_zero = true; auto filtered = v | std::views::filter([](const auto& val) { return val != 0; }); if (!std::ranges::empty(filtered)) { process_range(filtered); } else { process_range(v); // 过滤后为空,回退到原容器 } }
四、编译时已知条件:用constexpr if简化实现
如果条件是编译期常量(constexpr),直接用constexpr if在编译时消除不必要分支,返回的视图类型由编译期确定,无任何运行时开销:
int main() { std::vector<int> v = {0, 1, 2, 3, 4, 5, 6}; constexpr bool strategy_check_for_zero = true; // 编译期常量 auto selected = [&]() { if constexpr (strategy_check_for_zero) { return v | std::views::filter([](const auto& val) { return val != 0; }); } else { return v; } }(); process_range(selected); }
内容的提问来源于stack exchange,提问作者Damir Tenishev
相关产品推荐
相关产品推荐

