C++ 如何为vectors_predicate_view类实现可选的谓词模板参数
vectors_predicate_view类适配可选谓词参数的实现方案
核心调整思路
- 为第二个模板参数
Pred设置默认占位标记类型,标识「用户未显式传入谓词」的场景 - 用编译期分支逻辑区分两种构造行为:无谓词时直接返回不修改向量,有谓词时执行原有拆分逻辑,无运行时额外开销
- 对用户传入的谓词做编译期合法性校验,符合现有谓词继承
std::unary_function的适配要求
具体实现代码
首先定义占位标记类型,再实现类模板:
#include <vector> #include <utility> #include <functional> // 包含std::unary_function定义 #include <type_traits> // 包含类型判断工具 // 占位标记:用户未显式传入谓词时的默认模板参数 struct NoPredicate {}; template <class T, class Pred = NoPredicate> class vectors_predicate_view { public: vectors_predicate_view(std::vector<T>& vec_a, std::vector<T>& vec_b) { // 编译期判断当前是否为无谓词场景 if constexpr (std::is_same_v<Pred, NoPredicate>) { // 不执行任何操作,保留两个向量的原有内容 return; } else { // 校验传入谓词是否符合兼容要求 static_assert( std::is_base_of_v<std::unary_function<T, bool>, Pred>, "传入的谓词需继承自std::unary_function<T, bool>" ); // 原有拆分逻辑:暂存所有元素后清空原向量 std::vector<T> temp_storage; temp_storage.reserve(vec_a.size() + vec_b.size()); // 转移原向量元素到暂存区,避免冗余拷贝 std::move(vec_a.begin(), vec_a.end(), std::back_inserter(temp_storage)); std::move(vec_b.begin(), vec_b.end(), std::back_inserter(temp_storage)); vec_a.clear(); vec_b.clear(); // 按谓词筛选元素,分别放回两个向量 Pred pred{}; for (auto& elem : temp_storage) { if (pred(elem)) { vec_a.push_back(std::move(elem)); } else { vec_b.push_back(std::move(elem)); } } } } };
若需兼容不继承
std::unary_function的普通可调用类型,可将static_assert中的校验条件替换为std::is_invocable_r_v<bool, Pred, T>,支持任意接收T类型参数返回bool的可调用对象。
使用示例
无谓词场景(不修改原向量)
std::vector<int> a{1, 2, 3}, b{4, 5, 6}; // 不传入第二个模板参数,自动使用默认的NoPredicate vectors_predicate_view<int> no_op_view(a, b); // 执行后a、b内容保持不变
有谓词场景(执行拆分逻辑)
// 定义符合要求的谓词(继承自std::unary_function) struct is_even : std::unary_function<int, bool> { bool operator()(int x) const { return x % 2 == 0; } }; std::vector<int> a{1, 2, 3}, b{4, 5, 6}; // 显式传入谓词模板参数 vectors_predicate_view<int, is_even> split_view(a, b); // 执行后a存储所有偶数:2,4,6;b存储所有奇数:1,3,5
兼容旧标准的替代方案
若需使用C++17之前的标准(不支持if constexpr),可通过类模板特化为Pred=NoPredicate的场景单独提供空实现版本:
// 通用版本(传入谓词的场景) template <class T, class Pred = NoPredicate> class vectors_predicate_view { // 此处为上述带拆分逻辑的实现 }; // 特化版本(无谓词的场景) template <class T> class vectors_predicate_view<T, NoPredicate> { public: vectors_predicate_view(std::vector<T>&, std::vector<T>&) { // 空实现,不修改向量 } };
内容的提问来源于stack exchange,提问作者Martin Serdült
相关产品推荐
相关产品推荐

