以指向成员的指针作为比较器/"key"的 STD 算法
std algorithms with pointer to member as comparator/"key"
我经常发现自己使用std::sort
, std::max_element
等简单调用成员函数的lambda
std::vector<MyType> vec;
// populate...
auto m = std::max_element(std::begin(vec), std::end(vec),
[](const MyType& a, const MyType& b) { return a.val() < b.val()})
这感觉像是在浪费字符和失去清晰度。我知道我可以编写另一个函数/可调用对象,并将函数指针/可调用对象传递给这些算法函数,但我通常只需要在程序中进行一次排序,这并不是解决问题的好方法。理想情况下,我想做的是:
auto m = std::max_element(std::begin(vec), std::end(vec), &MyType::val);
,并根据其val()
s对对象进行排序。我忽略了标准库的某些部分,可以帮助我做到这一点吗?或者其他简单的方法?我想让排序和搜索的依据尽可能明显。
我知道,只是&MyType::val
是不够的,我正在寻找的东西,也许可以包装它,或提供类似的功能,而不模糊的意义。
您可以使用std::mem_fn
(或std::tr1::mem_fn
)
int main()
{
std::vector<MyType> vec;
auto m = std::max_element(std::begin(vec), std::end(vec), compare_by(std::mem_fn(&MyType::field)));
}
当然,这假设您的工具箱中有一个像compare_by
这样的实用程序(您应该:)):
template <typename F>
struct CompareBy {
explicit CompareBy(F&& f) : f(std::forward<F>(f)) {}
template <typename U, typename V>
bool operator()(U const& u, V const& v) const {
return f(u) < f(v);
}
private:
F f;
};
template <typename F>
CompareBy<F> compare_by(F&& f) { return CompareBy<F>(std::forward<F>(f)); }
查看Live On Coliru
您可以在不引入任何新函数(无论是否模板化)的情况下实现。
只使用bind
和std::less
auto m = std::max_element(vec.begin(), vec.end(),
bind(less<>(), bind(&MyType::val, _1), bind(&MyType::val, _2)));
模板比较器可以帮助您:
template <typename StructureType,
typename MemberType,
MemberType StructureType::*member>
bool comparator(const StructureType& the_first, const StructureType& the_second)
{
return the_first.*member < the_second.*member;
}
http://ideone.com/K8ytav 一点类型特征的魔力当然可以让你避免写类型
如何一次重载operator<
为您的自定义类型?这可以自然地在类内部(或直接在类旁边)完成,然后在迭代器旁边不需要进一步的参数。
传递val()
函数是不可能的,因为必须传递一个二进制运算符。
编辑:在阅读了其他有价值的替代方案(也是sehe的好回应)之后,我想确认我在下面的评论中已经提到的:在我看来,没有什么比lambda表达式的可读性,局部性和灵活性更好的了(-冒着写两次段落的风险)。
@Ryan Haining:我建议你保持原封不动
为了避免使用std::mem_fn
,对这个答案进行改进,可以为compare_by
函数提供一个指向成员重载的指针。
std::sort(std::begin(vec), std::end(vec), compare_by(&MyType::field));
std::sort(std::begin(vec), std::end(vec), compare_by(&MyType::field, std::greater<>{}));
实现
的代码#include <functional> // std::less
#include <utility> // std::move
#include <type_traits> // std::is_invocable_r
// Forward declaration
template<typename R, typename T, typename F = std::less<R>>
auto compare_by(R T::*, F = F{});
// Implementation
namespace detail {
template<typename T, typename F>
struct compare_by_t;
template<typename R, typename T, typename F>
struct compare_by_t<R T::*, F> : private F
{
compare_by_t(F&& f, R T::*m): F{std::move(f)}, _member{m} {}
R T::* _member;
bool operator()(T const& x, T const& y) const
{
return F::operator()(x .* _member, y .* _member);
}
};
} // detail
template<typename R, typename T, typename F>
auto compare_by(R T::* member, F f)
{
static_assert(std::is_invocable_r<bool, F, R, R>::value);
return detail::compare_by_t<R T::*, F>{ std::move(f), member };
}
- 为什么这个运算符<重载函数对 STL 算法不可见?
- 基于ELO的团队匹配算法
- C++选择排序算法中的逻辑错误
- 有没有办法将谓词中的元素偏移量传递给 std 算法?
- C++A*算法并不总是在路径中具有目标节点
- 排序算法c++
- 构建可组合有向图(扫描仪生成器的汤普森构造算法)
- 算法问题:查找从堆栈中弹出的所有序列
- 下面是排序算法O(n)吗
- KMP算法和LPS表构造的运行时间
- 为什么我的排序算法会更改数组值
- 求最大元素位置的分治算法
- 具有非整数边容量的最大流量的Dinic算法
- 到连接组件算法的问题(递归)
- STL算法函数在多个一维容器上的使用
- 读取最后一行代码算法 - c++ 时出现问题
- 括号更改 O(n) 算法
- std::unordered_map 搜索算法是如何实现的?
- 如何实现高效的算法来计算大型数据集的多个不同值?
- 以指向成员的指针作为比较器/"key"的 STD 算法