C++17重写std::min_element时如何用模板参数简洁表示迭代器解引用类型
解决方法:合并重载的实现
你要的默认参数版本可以通过std::iterator_traits获取迭代器的值类型实现,不需要额外的重载,核心原因是模板默认参数不能依赖函数形参,因此你不能在默认模板参数中直接用decltype(*first)(first是函数参数,不在模板参数的作用域解析),改用迭代器萃取的类型即可:
#include <iterator> #include <functional> template< class ForwardIt, class Compare = std::less<typename std::iterator_traits<ForwardIt>::value_type> > ForwardIt min_element(ForwardIt first, ForwardIt last, Compare comp = Compare{}) { if (first == last) return first; ForwardIt min_it = first; while (++first != last) { if (comp(*first, *min_it)) { min_it = first; } } return min_it; }
如果希望适配更多场景(比如代理迭代器、自定义的透明比较器特化),可以把默认比较器换成C++14就支持的透明std::less<>,不需要显式指定值类型,会自动推导比较的参数类型,灵活度更高:
template< class ForwardIt, class Compare = std::less<void> > ForwardIt min_element(ForwardIt first, ForwardIt last, Compare comp = Compare{}) { // 实现逻辑同上 }
原有实现的问题
- 空范围未定义行为:你写的双参数重载里直接解引用
*first,如果传入的是空范围(first == last),这一步直接触发UB,属于严重bug - 多余的拷贝开销:
auto e = *first会对解引用的结果做一次无意义的拷贝,对于非平凡类型会增加不必要的性能损耗 - 语法错误:示例代码里多了一层冗余的大括号,编译无法通过
额外优化建议
- 如果要完全对齐C++17的标准要求,可以给函数加上
constexpr修饰,支持编译期计算 - 可以通过
static_assert加std::forward_iterator_tag校验迭代器类别,提前拦截不符合要求的迭代器输入 - 比较函数需要满足严格弱序约定,不要传入会修改比较对象、或者不符合序要求的函数
内容的提问来源于stack exchange,提问作者Captain Giraffe
相关产品推荐
相关产品推荐

