基于C++14实现结构体vector操作(移除、查找等)的通用简化封装需求
太懂这种烦躁了!每次用C标准库处理vector里的结构体,写erase-remove_if或者find_if那一大串代码,光迭代器和lambda的语法就够让人头疼的,完全理解你想改成Java那种简洁调用的需求。在C14里完全可以实现这种通用的简化封装,我给你一步步说怎么做:
一、移除元素的通用封装
我们可以写一个模板函数,把erase和remove_if的逻辑全部封装在内部,你只需要传入目标vector和判断条件的lambda就行,不用再跟迭代器打交道。
封装代码
#include <vector> #include <algorithm> // 通用移除元素函数:接收vector引用和判断谓词 template <typename T, typename Predicate> void removeElement(std::vector<T>& vec, Predicate pred) { // 内部自动处理erase-remove_if流程 vec.erase(std::remove_if(vec.begin(), vec.end(), std::move(pred)), vec.end()); }
调用示例
这就是你想要的简洁写法,完全不用管迭代器的细节:
// 假设MYSTRUCT是你的自定义结构体类型 std::vector<MYSTRUCT> selections = /* 初始化你的vector */; // 一行代码完成移除判断条件匹配的元素 removeElement(selections, [](const MYSTRUCT& item) { return item.text == L".."; });
这里用了模板的自动类型推导(C++14对模板参数推导的支持已经足够完善),不管你用什么结构体类型,这个函数都能直接用。std::move(pred)是为了避免拷贝lambda对象,提升一点效率,不用也不影响功能。
二、查找元素的通用封装
同样的思路,我们把find_if和迭代器判断的逻辑封装起来,让你只需要关注查找的判断条件,不用手动处理迭代器的声明和空判断。
封装代码(返回指针,找不到返回nullptr)
这种写法比较灵活,找不到元素时返回空指针,你可以自己决定后续处理:
template <typename T, typename Predicate> T* findElement(std::vector<T>& vec, Predicate pred) { auto iter = std::find_if(vec.begin(), vec.end(), pred); return (iter != vec.end()) ? &(*iter) : nullptr; } // 对应const版本的vector,返回const指针 template <typename T, typename Predicate> const T* findElement(const std::vector<T>& vec, Predicate pred) { auto iter = std::find_if(vec.begin(), vec.end(), pred); return (iter != vec.end()) ? &(*iter) : nullptr; }
调用示例
std::vector<MYSTRUCT> driveItems = /* 初始化你的vector */; std::wstring targetPath = L"你要找的路径"; // 一行代码完成查找 MYSTRUCT* foundItem = findElement(driveItems, [&](const MYSTRUCT& elem) { return elem.path == targetPath; }); // 后续处理 if (foundItem) { // 直接通过*foundItem访问找到的结构体成员 wprintf(L"找到路径:%ls\n", foundItem->path.c_str()); } else { wprintf(L"未找到目标元素\n"); }
可选:返回引用(找不到抛出异常)
如果你确定要找的元素一定存在,或者想用异常处理找不到的情况,可以写这个版本:
#include <stdexcept> template <typename T, typename Predicate> T& findElementOrThrow(std::vector<T>& vec, Predicate pred) { auto iter = std::find_if(vec.begin(), vec.end(), pred); if (iter != vec.end()) { return *iter; } throw std::runtime_error("未找到匹配的元素"); }
调用时可以直接用一行代码获取元素(如果不需要异常处理的话):
// 假设元素一定存在,直接获取引用 MYSTRUCT& foundItem = findElementOrThrow(driveItems, [&](const MYSTRUCT& elem) { return elem.path == targetPath; });
小补充:关于你想要的极简lambda写法
你伪代码里的findElement(driveItems, { return elem.path == path; });这种写法在C++14里暂时做不到,因为编译器没法识别单独的{...}是lambda表达式——必须加上[]捕获列表(比如[&]捕获外部变量)才能让编译器知道这是一个lambda。不过现在的写法已经比原有的标准库调用简洁太多了,完全省去了迭代器相关的所有冗余代码。
而且这些封装都是类型安全的,比用宏实现要可靠得多,不会出现宏常见的各种奇怪问题。
内容来源于stack exchange

