基于getter成员函数对STL容器进行排序,而不编写额外的代码

jpo*_*o38 1 c++ sorting stl

让我们考虑以下代码示例:

// Example program
#include <iostream>
#include <string>
#include <algorithm>

class A
{
public:
    A( const std::string& name ) : name( name ) {}

    inline const std::string& getName() const { return name; }

private:
    std::string name;
};

int main()
{
    std::vector<A> v;
    v.push_back( A("b") );
    v.push_back( A("a") );

    // want to sort the container, based on it's name!
}
Run Code Online (Sandbox Code Playgroud)

我知道如何做到这一点(或者定义一个内部或外部operator<,或者声明一个functor struct/class,提供一个operator()并将它传递给std::sortfonction),例如:

bool operator<( const A& a ) const
{
    return getName() < a.getName();
}
Run Code Online (Sandbox Code Playgroud)

但是,每次我想根据包含的类属性对容器进行排序时,我都懒得这样做,特别是当类为它提供getter函数时.

是否可以根据类成员函数结果值请求排序(如果有一个比较器可用,显然)?

就像是:

std::sort( v.begin(), v.end(), &(A::getName) );
Run Code Online (Sandbox Code Playgroud)

无需声明新的运算符或函子?

可选问题:如果vector包含指针(std::vector<A*> v)...,单行语句可以根据A::getName结果对其进行排序,该怎么办?

Hol*_*olt 7

您可以使用lambda函数对矢量进行排序:

std::sort(v.begin(), v.end(), [] (A const& a, A const& b) {
        return a.getName() < b.getName();
    });
Run Code Online (Sandbox Code Playgroud)

它比你的版本长,但你不需要在调用之前写任何东西sort.

如果你需要做的那种东西的时候,你可以把一切都放在一个小函子(并允许其两个工作A,A*和智能指针),它使用mem_fn(感谢@TC):

template <typename T, typename R>
struct cmp_attr {

    using fun_t = R (T::*) () const;

    cmp_attr (fun_t g) : _g(g) { }

    template <typename U>
    bool operator() (U const& a, U const& b) const {
        auto fn = std::mem_fn(_g);
        return fn(a) < fn(b);
    }

private:
    fun_t _g;
};

// Utility function to have template parameters deduced, a like std::make_pair
template<typename T, typename R>
auto make_cmp_attr (R (T::*g) () const) {
    return cmp_attr<T, R>(g);
}
Run Code Online (Sandbox Code Playgroud)

然后:

struct A { const std::string& getName(); }
struct B: public A { }

std::vector<A> v1; // vector of A
std::sort(v1.begin(), v1.end(), make_cmp_attr(&A::getName));
std::vector<A*> v2; // vector of A*
std::sort(v2.begin(), v2.end(), make_cmp_attr(&A::getName));
std::vector<B> v3; // vector of child class
std::sort(v3.begin(), v3.end(), make_cmp_attr(&A::getName));
std::vector<B*> v4; // vector of pointer of child class
std::sort(v4.begin(), v4.end(), make_cmp_attr(&A::getName));
Run Code Online (Sandbox Code Playgroud)