如何筛选并转换C++ Vector至另一类型?含范围过滤及错误排查
InfoBlob转Action的范围处理问题与解决方案
背景需求
已定义InfoBlob类及Action、Emotion枚举类,需实现函数:
- 输入:
std::vector<InfoBlob>类型的blobs - 输出:
std::vector<Action>类型的actions - 转换规则:仅在第一个HAPPY blob到最后一个SAD blob的范围内执行转换,且仅处理
emotion为HAPPY或SAD的blob。
核心问题
- 如何将转换操作限定在第一个HAPPY blob至最后一个SAD blob的范围内?
- 如何在满足“blob的emotion为HAPPY或SAD”的过滤条件下,完成
vector<InfoBlob>到vector<Action>的转换?
当前编译错误
尝试先过滤再转换时,出现如下编译错误:
error: no match for ‘operator=’ (operand types are ‘std::vector<ex4::Action>’ and ‘std::ranges::transform_view<std::ranges::filter_view<std::ranges::ref_view<std::vector<ex4::InfoBlob> >, task03(std::vector<ex4::InfoBlob>)::<lambda(ex4::InfoBlob)> >, task03(std::vector<ex4::InfoBlob>)::<lambda(ex4::InfoBlob)> >’) 35 | });
相关类定义
enum class Emotion : char { HAPPY, SAD, PERPLEXED, STRESSED }; enum class Action : char { RUN, LAUGH, WORRY, WEEP, PLAN, PLOT, READ }; class InfoBlob { public: InfoBlob(int entropy, float spin, Emotion emotion) noexcept : entropy{entropy}, spin{spin}, emotion{emotion} { } int getEntropy() const noexcept { return entropy; } float getSpin() const noexcept { return spin; } Emotion getEmotion() const noexcept { return emotion; } bool operator==(const InfoBlob& other) const noexcept { return entropy == other.entropy && spin == other.spin && emotion == other.emotion; } };
当前代码
#include "task03.h" #include <iostream> #include <algorithm> #include <ranges> using namespace ex4; std::vector<ex4::Action> task03(std::vector<InfoBlob> blobs){ std::vector<ex4::Action> actions; actions = blobs | std::ranges::views::filter([](ex4::InfoBlob blob){ return blob.getEmotion() == ex4::Emotion::HAPPY || blob.getEmotion() == ex4::Emotion::SAD; }) | std::ranges::views::transform([](ex4::InfoBlob blob){ if(blob.getSpin() > blob.getEntropy()) return ex4::Action::PLOT; else return ex4::Action::RUN; }); return actions; }
解决方案
1. 解决编译错误:Range View转Vector
C++20的Range View(如filter_view、transform_view)不能直接赋值给std::vector,需要通过std::ranges::copy将view中的元素拷贝到vector,或者直接用view构造vector:
- C++20方案:用
std::ranges::copy配合std::back_inserter - C++23方案:用
std::ranges::to直接构造vector
2. 限定转换范围:第一个HAPPY到最后一个SAD
步骤:
- 用
std::find_if正向遍历找到第一个emotion为HAPPY的迭代器 - 用
std::find_if反向遍历找到最后一个emotion为SAD的迭代器,再通过base()转换为正向迭代器 - 检查范围有效性:确保HAPPY在SAD之前,且两个迭代器均有效
完整修正代码
#include "task03.h" #include <iostream> #include <algorithm> #include <ranges> #include <iterator> using namespace ex4; std::vector<ex4::Action> task03(std::vector<InfoBlob> blobs) { std::vector<ex4::Action> actions; // 找到第一个HAPPY blob的迭代器 auto first_happy = std::find_if(blobs.begin(), blobs.end(), [](const InfoBlob& blob) { return blob.getEmotion() == Emotion::HAPPY; }); // 找到最后一个SAD blob的迭代器(反向转正向) auto last_sad = std::find_if(blobs.rbegin(), blobs.rend(), [](const InfoBlob& blob) { return blob.getEmotion() == Emotion::SAD; }).base(); // 确保范围有效:存在HAPPY和SAD,且HAPPY在SAD之前 if (first_happy != blobs.end() && last_sad != blobs.begin() && first_happy < last_sad) { auto target_range = std::ranges::subrange(first_happy, last_sad); auto processed = target_range | std::ranges::views::filter([](const InfoBlob& blob) { return blob.getEmotion() == Emotion::HAPPY || blob.getEmotion() == Emotion::SAD; }) | std::ranges::views::transform([](const InfoBlob& blob) { return blob.getSpin() > blob.getEntropy() ? Action::PLOT : Action::RUN; }); // C++20:拷贝到vector std::ranges::copy(processed, std::back_inserter(actions)); // 若支持C++23,可替换为: // std::vector<ex4::Action> actions = processed | std::ranges::to<std::vector>(); } return actions; }
关键细节说明
- 用
const InfoBlob&作为lambda参数,避免不必要的拷贝开销 - 反向迭代器转正向时,
rend().base()等价于begin(),需额外判断last_sad != blobs.begin() - 范围有效性检查避免了空区间或逆序区间的无效操作
内容的提问来源于stack exchange,提问作者callum arul
相关产品推荐
相关产品推荐

