我经常发现自己将std::sort
、std::max_element
等与lambda一起使用,而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()})
这感觉像是字符的浪费和清晰度的丧失。我知道我可以编写另一个函数/callable,并将函数指针/callable对象传递给这些算法函数,但我经常需要在程序中只做一次这样的排序,这并不是解决问题的好方法。理想情况下,我想说的是:
auto m = std::max_element(std::begin(vec), std::end(vec), &MyType::val);
并且让对象按照它们的val()
排序。有没有我忽略的stdlib的某些部分可以帮助我做到这一点?或者是另一种简单的方法呢?我想让排序或搜索的内容变得尽可能明显。
我意识到仅仅&MyType::val
是不够的,我正在寻找一些可以包装它的东西,或者提供类似的功能而不模糊它的含义。
发布于 2014-05-12 03:42:10
一个模板化的比较器可以帮助你:
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;
}
一些类型特征的魔力可以让你避免编写类型。
发布于 2014-05-12 03:23:59
为你的自定义类型重载一次operator<
怎么样?这可以在类中自然地完成(或者直接在它旁边),然后除了迭代器之外就不需要进一步的参数了。
传递你的val()
函数是不可能的,因为你必须传递一个二元操作符。
编辑:在阅读了其他有价值的替代方案(也看到他很好的回应)后,我想确认一下我在下面的评论中已经提到的:在我看来,没有什么比lambda表达式的可读性、局部性和灵活性更好的了(--关于写两次某些段落的风险)。
@Ryan Haining:我建议你保留原来的帖子。
发布于 2018-12-11 07:42:41
为了避免需要使用std::mem_fn
,对sehes答案的改进是为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 };
}
https://stackoverflow.com/questions/23596840
复制相似问题