std算法,指向成员的指针作为比较器/" key"

时间:2014-05-11 19:16:18

标签: c++ algorithm c++11 pointer-to-member

我经常发现自己使用std::sortstd::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()对对象进行排序。我有什么部分stdlib可以帮助我解决这个问题吗?或另一种简单的方法吗?我想尽可能明显地进行排序或搜索。

我知道只有&MyType::val是不够的,我正在寻找可以包装它的东西,或提供类似的功能而不会影响其含义。

5 个答案:

答案 0 :(得分:16)

您可以使用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

答案 1 :(得分:3)

你可以without引入任何新功能(模板化或不模板化)。

Just使用bindstd::less

auto m = std::max_element(vec.begin(), vec.end(), 
    bind(less<>(), bind(&MyType::val, _1), bind(&MyType::val, _2)));

答案 2 :(得分:1)

模板化比较器可以帮助您:

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

一些类型特质魔术当然可以让你避免写这种类型。

答案 3 :(得分:0)

为自定义类型重载operator<怎么样?这可以在类中自然地完成(或者直接在它旁边),然后在迭代器旁边不需要进一步的参数。

无法传递val()函数,因为您必须传递二元运算符。

编辑:在阅读了其他有价值的替代方案(也是很好的回答)之后,我想确认一下我在下面的评论中已经提到的内容:在我看来,没有什么比lambda表达的可读性,局部性和灵活性更好了( - - 两次写一些段落的风险)。

@Ryan Haining:我建议你保留原来的帖子。

答案 4 :(得分:0)

对sehes答案的一种改进,以避免使用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 };
}