能否用std::any_of检查范围值?id()实现及标准库替代咨询
id()谓词生成函数的优化实现与标准库替代方案 你的现有实现存在的问题
你当前的实现使用std::function存在两个明显缺陷:
- 性能开销:
std::function是类型擦除容器,会引入运行时间接调用的成本,对于简单的相等比较来说完全没必要。 - 生命周期风险:lambda捕获的是传入参数的引用,如果传入临时对象(比如
id(std::string("!!!"))中的临时std::string),id函数返回后临时对象会被销毁,lambda中的引用就会悬空,触发未定义行为。
更优的实现方案
方案1:C++14+ 简洁lambda版本(推荐)
利用C++14的自动返回类型推导,直接返回捕获值副本的lambda,避免类型擦除和引用悬空:
#include <concepts> template <std::equality_comparable T> constexpr auto id(T value) { return [value = std::move(value)](const T& other) noexcept(noexcept(value == other)) { return value == other; }; }
- 用
std::move转移传入值的所有权,减少不必要的拷贝。 - 标记为
constexpr,支持编译期场景下的调用。 noexcept推导确保相等比较无异常时,谓词也标记为无异常,优化编译器行为。
方案2:自定义仿函子类(C++11兼容)
如果需要兼容C++11,可手动定义仿函子类替代lambda:
#include <concepts> template <std::equality_comparable T> struct EqualTo { T value; constexpr bool operator()(const T& other) const noexcept(noexcept(value == other)) { return value == other; } }; template <std::equality_comparable T> constexpr EqualTo<T> id(T value) { return EqualTo<T>{std::move(value)}; }
这个方案同样避免了std::function的开销,且生命周期安全。
标准库中的替代方案
标准库没有直接提供和你需求完全匹配的id()函数,但可以通过现有组件组合实现类似效果:
- C++11+:
std::bind+std::equal_to
缺点是写法冗长,可读性差,且#include <functional> std::ranges::any_of(my_string, std::bind(std::equal_to<char>(), 'j', std::placeholders::_1));std::bind的性能不如直接的lambda或仿函子。 - C++20+:
std::ranges::bind_back
C++20引入的bind_back可以将二元谓词转换为绑定了第二个参数的一元谓词:
这个方案比#include <functional> std::ranges::any_of(my_string, std::bind_back(std::equal_to<char>(), 'j'));std::bind简洁,但依然不如自定义id()直观。
总结
最推荐的是C++14+的lambda版本,它兼顾简洁性、性能和安全性。如果必须依赖标准库,C++20的std::bind_back是相对合适的替代方案。
内容的提问来源于stack exchange,提问作者stefaanv
相关产品推荐
相关产品推荐

