C++谓词布尔运算组合实现及相关技术问询
C++谓词布尔运算适配实现的技术问题解答
1. 实现效率与运行时开销消除
- 基于模板的
compose实现本身是编译期展开的,只要你的谓词是可内联的(比如lambda、轻量仿函数),编译器基本能自动优化掉中间适配层,不会有额外运行时开销。 - 要近乎完全消除开销,得做到这几点:
- 保证所有谓词类型是可平凡构造/析构的,避免不必要的对象构造成本;
- 用
constexpr修饰compose的调用运算符和谓词逻辑,强制编译期计算; compose里只存谓词的值或引用(优先值语义,方便编译器内联),别加多余状态;- 开启编译器优化选项(比如
-O2//O2),让编译器完成内联和死代码消除。
2. 对compose模板参数的谓词约束
- 当然可以,C++20及以上推荐用**概念(Concepts)**来做清晰的约束,比如先定义一个通用的谓词概念:
然后在template<typename F, typename... Args> concept Predicate = requires(F f, Args... args) { { f(args...) } -> std::convertible_to<bool>; };compose模板里直接用这个概念约束参数:template<Predicate<Args...> P1, Predicate<Args...> P2, typename... Args> struct compose_and { // 你的实现逻辑 }; - 如果是C++17及更早版本,用SFINAE结合
std::is_invocable_r做编译期检查:template<typename P1, typename P2, typename... Args, std::enable_if_t<std::conjunction_v< std::is_invocable_r<bool, P1, Args...>, std::is_invocable_r<bool, P2, Args...> >, int> = 0> struct compose_and { // 你的实现逻辑 };
3. 用operator&&替代and_fn
- 可以实现,但得让
compose生成的适配器类型重载operator&&,同时约束操作数的谓词类型:- 给适配器类型加
operator&&重载,接受另一个谓词,返回新的compose适配器:template<Predicate<Args...> P> auto operator&&(P&& other) const { return compose_and<std::decay_t<decltype(*this)>, std::decay_t<P>, Args...>{*this, std::forward<P>(other)}; } - 要支持任意参数的谓词,要么用模板化的
operator&&,要么用可变参数的概念约束,确保两个谓词能接受完全相同的参数列表。另外可以加推导指引,让编译器自动推断参数类型。
- 给适配器类型加
4. 直接传入布尔类型的operator&&替代lambda
- 不行。内置的
operator&&不是一个可调用实体(比如函数指针、仿函数),没法直接作为参数传入模板。而lambda是编译器生成的匿名仿函数,有具体的类型,能被模板推导和存储。 - 替代方案:用标准库的
std::logical_and<void>(C++14及以上),它是通用的逻辑与仿函数,能接受任意可转成bool的操作数,比如:auto and_fn = [](auto&& p1, auto&& p2) { return compose<std::logical_and<void>, decltype(p1), decltype(p2)>{std::forward<decltype(p1)>(p1), std::forward<decltype(p2)>(p2)}; };
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

