如何返回不同容器对应的range?C++多容器范围返回问题
解决不同容器返回不同Range类型的编译问题
你的问题核心是std::ranges::views::all对不同容器返回的view类型存在差异(比如std::array对应std::ranges::array_view,std::vector对应std::ranges::vector_view),而lambda的auto返回类型要求所有分支返回完全相同的类型,因此编译失败。以下是两种可行的解决方法:
方法一:使用类型擦除的std::ranges::any_view
std::ranges::any_view是C++20提供的类型擦除工具,可以容纳任意满足range概念的对象,同时保留遍历能力。只需将lambda的返回类型指定为std::ranges::any_view<T>(T是容器元素类型),所有分支的view都会隐式转换为该类型。
示例代码:
#include <ranges> #include <array> #include <vector> #include <list> #include <deque> enum class sound_category { voice, mono, music, sfx }; struct SoundSystem { std::array<int, 10> dialogue_voices; std::vector<int> mono_voices; std::list<int> music_voices; std::deque<int> sfx_voices; }; int main() { sound_category category = sound_category::voice; SoundSystem* system = new SoundSystem(); // 指定返回类型为any_view<int>,统一所有分支的返回类型 auto range = [category, system]() -> std::ranges::any_view<int> { switch(category) { case sound_category::voice: return std::ranges::views::all(system->dialogue_voices); case sound_category::mono: return std::ranges::views::all(system->mono_voices); case sound_category::music: return std::ranges::views::all(system->music_voices); default: return std::ranges::views::all(system->sfx_voices); } }(); // 正常遍历range for (int elem : range) { // 处理元素 } delete system; return 0; }
优缺点:实现简单,代码改动小;类型擦除会带来轻微的性能开销,适合绝大多数场景。
方法二:使用std::variant存储不同Range类型
如果对性能要求极高,不想承担类型擦除的开销,可以用std::variant存储所有可能的view类型。使用时通过std::visit访问variant中的具体range。
示例代码:
#include <ranges> #include <variant> #include <array> #include <vector> #include <list> #include <deque> enum class sound_category { voice, mono, music, sfx }; struct SoundSystem { std::array<int, 10> dialogue_voices; std::vector<int> mono_voices; std::list<int> music_voices; std::deque<int> sfx_voices; }; int main() { sound_category category = sound_category::voice; SoundSystem* system = new SoundSystem(); // 声明包含所有可能view类型的variant using RangeVariant = std::variant< decltype(std::ranges::views::all(std::declval<std::array<int,10>>())), decltype(std::ranges::views::all(std::declval<std::vector<int>>())), decltype(std::ranges::views::all(std::declval<std::list<int>>())), decltype(std::ranges::views::all(std::declval<std::deque<int>>())) >; auto range_variant = [category, system]() -> RangeVariant { switch(category) { case sound_category::voice: return std::ranges::views::all(system->dialogue_voices); case sound_category::mono: return std::ranges::views::all(system->mono_voices); case sound_category::music: return std::ranges::views::all(system->music_voices); default: return std::ranges::views::all(system->sfx_voices); } }(); // 使用std::visit访问variant中的range std::visit([](auto&& range) { for (int elem : range) { // 处理元素 } }, range_variant); delete system; return 0; }
优缺点:无类型擦除的性能损失;但需要显式声明所有可能的view类型,使用时必须通过std::visit处理,代码复杂度稍高。
内容的提问来源于stack exchange,提问作者user3001150
相关产品推荐
相关产品推荐

