Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 排序谓词的链接(例如,对于std::sort)_C++_Stl_Sorting_Compare_Predicate - Fatal编程技术网

C++ 排序谓词的链接(例如,对于std::sort)

C++ 排序谓词的链接(例如,对于std::sort),c++,stl,sorting,compare,predicate,C++,Stl,Sorting,Compare,Predicate,您可以将函数指针、函数对象(或boost lambda)传递给std::sort,以定义要排序的容器元素的严格弱排序 然而,有时(我已经多次提到这一点),您希望能够链接“原始”比较 一个简单的例子是,如果您正在对表示联系人数据的对象集合进行排序。有时你会想按姓、名、区号排序。其他时间名字,姓氏-还有其他时间年龄,名字,区号。。。等 last name, first name, area code age, first name, area code 现在,您当然可以为每种情况编写一个额外的函数对

您可以将函数指针、函数对象(或boost lambda)传递给std::sort,以定义要排序的容器元素的严格弱排序

然而,有时(我已经多次提到这一点),您希望能够链接“原始”比较

一个简单的例子是,如果您正在对表示联系人数据的对象集合进行排序。有时你会想按姓、名、区号排序。其他时间名字,姓氏-还有其他时间年龄,名字,区号。。。等

last name, first name, area code age, first name, area code 现在,您当然可以为每种情况编写一个额外的函数对象,但这违反了DRY原则——尤其是如果每次比较都不那么琐碎的话

似乎您应该能够编写比较函数的层次结构-低级函数执行单个、基本的比较(例如,first name 这种方法的问题在于std::sort采用了一个二进制谓词——该谓词只能返回bool。因此,如果你正在编写它们,你就无法分辨“false”是否表示等于或大于。您可以让较低级别的谓词返回一个int,有三种状态,但是您必须先将它们封装在较高级别的谓词中,然后才能单独与std::sort一起使用

总之,这些都不是无法克服的问题。这似乎比它应该做的更难——而且肯定需要一个助手库实现

因此,是否有人知道任何预先存在的库(特别是如果是std或boost库)可以在这里提供帮助,或者对此有其他想法

[更新]

正如在一些评论中提到的,我已经开始编写自己的类实现来管理它。这是一个相当小的问题,一般来说可能会有一些问题。但在此基础上,对任何感兴趣的人来说,课程就在这里:

以下是一些帮助函数(以避免指定模板参数):


处理此问题的一种常规方法是在多个过程中进行排序,并使用稳定的排序。请注意,
std::sort
通常不稳定。但是,有
std::stable\u sort


这就是说,我将围绕返回三态(表示更少、相等、更大)的函子编写一个包装器。

std::sort
不能保证是稳定的,因为稳定的排序通常比不稳定的排序慢。。。所以多次使用稳定排序看起来像是性能问题的一个处方

是的,这类人要求一个谓词真的很遗憾:
我认为除了创建一个接受三态函数向量的函子之外没有其他方法…

你可以像这样构建一个小链接系统:

struct Type {
  string first, last;
  int age;
};

struct CmpFirst {
  bool operator () (const Type& lhs, const Type& rhs) { return lhs.first < rhs.first; }
};

struct CmpLast {
  bool operator () (const Type& lhs, const Type& rhs) { return lhs.last < rhs.last; }
};

struct CmpAge {
  bool operator () (const Type& lhs, const Type& rhs) { return lhs.age < rhs.age; }
};

template <typename First, typename Second>
struct Chain {
  Chain(const First& f_, const Second& s_): f(f_), s(s_) {}

  bool operator () (const Type& lhs, const Type& rhs) {
    if(f(lhs, rhs))
      return true;
    if(f(rhs, lhs))
      return false;

    return s(lhs, rhs);
  }

  template <typename Next>
  Chain <Chain, Next> chain(const Next& next) const {
     return Chain <Chain, Next> (*this, next);
  }

  First f;
  Second s;
};

struct False { bool operator() (const Type& lhs, const Type& rhs) { return false; } };

template <typename Op>
Chain <False, Op> make_chain(const Op& op) { return Chain <False, Op> (False(), op); }
结构类型{
先串,后串;
智力年龄;
};
结构CmpFirst{
bool运算符()(const-Type&lhs,const-Type&rhs){返回lhs.first
然后使用它:

vector <Type> v;  // fill this baby up

sort(v.begin(), v.end(), make_chain(CmpLast()).chain(CmpFirst()).chain(CmpAge()));
向量v;//把这个婴儿灌满 排序(v.begin()、v.end()、make_-chain(CmpLast()).chain(CmpFirst()).chain(CmpAge());

最后一行有点冗长,但我认为它的意图是明确的。

链接解决方案是冗长的。您还可以将boost::bind与std::logical_结合使用,并构建排序谓词。有关更多信息,请参阅链接文章:

您可以尝试以下方法:

用法:

struct Citizen {
    std::wstring iFirstName;
    std::wstring iLastName;
};

ChainComparer<Citizen> cmp;
cmp.Chain<std::less>( boost::bind( &Citizen::iLastName, _1 ) );
cmp.Chain<std::less>( boost::bind( &Citizen::iFirstName, _1 ) );

std::vector<Citizen> vec;
std::sort( vec.begin(), vec.end(), cmp );
struct-Citizen{
std::wstring iFirstName;
std::wstring iLastName;
};
链式比较器;
Chain(boost::bind(&Citizen::iLastName,_1));
Chain(boost::bind(&Citizen::iFirstName,_1));
std::vec;
排序(vec.begin(),vec.end(),cmp);
实施:

template <typename T>
class ChainComparer {
public:

    typedef boost::function<bool(const T&, const T&)> TComparator;
    typedef TComparator EqualComparator;
    typedef TComparator CustomComparator;

    template <template <typename> class TComparer, typename TValueGetter>
    void Chain( const TValueGetter& getter ) {

        iComparers.push_back( std::make_pair( 
            boost::bind( getter, _1 ) == boost::bind( getter, _2 ), 
            boost::bind( TComparer<TValueGetter::result_type>(), boost::bind( getter, _1 ), boost::bind( getter, _2 ) ) 
        ) );
    }

    bool operator()( const T& lhs, const T& rhs ) {
        BOOST_FOREACH( const auto& comparer, iComparers ) {
            if( !comparer.first( lhs, rhs ) ) {
                return comparer.second( lhs, rhs );
            }
        }

        return false;
    }

private:
    std::vector<std::pair<EqualComparator, CustomComparator>> iComparers;
};
模板
类链比较器{
公众:
typedef boost::函数t比较器;
typedef t压缩机-均衡器压缩机;
typedef TComparator自定义比较器;
模板
空链(常数TValueGetter和getter){
i比较者。推回(标准::制作配对(
boost::bind(getter,_1)==boost::bind(getter,_2),
boost::bind(TComparer(),boost::bind(getter,_1),boost::bind(getter,_2))
) );
}
布尔运算符()(常数T和lhs、常数T和rhs){
BOOST_FOREACH(常量自动和比较器、iComparers){
如果(!比较器优先(左、右)){
返回比较器秒(左、右);
}
}
返回false;
}
私人:
std::向量i比较;
};

<>代码> C++ 11中的变量模板给出了一个较短的选项:

    #include <iostream>
    using namespace std;

    struct vec { int x,y,z; };

    struct CmpX {
      bool operator() (const vec& lhs, const vec& rhs) const 
      { return lhs.x < rhs.x; }
    };

    struct CmpY {
      bool operator() (const vec& lhs, const vec& rhs) const 
      { return lhs.y < rhs.y; }
    };

    struct CmpZ {
      bool operator() (const vec& lhs, const vec& rhs) const 
      { return lhs.z < rhs.z; }
    };

    template <typename T>
    bool chained(const T &, const T &) {
      return false;
    }

    template <typename CMP, typename T, typename ...P>
    bool chained(const T &t1, const T &t2, const CMP &c, P...p) {
      if (c(t1,t2)) { return true;          }
      if (c(t2,t1)) { return false;         }
      else          { return chained(t1, t2, p...); }
    }

    int main(int argc, char **argv) {
      vec x = { 1,2,3 }, y = { 2,2,3 }, z = { 1,3,3 };
      cout << chained(x,x,CmpX(),CmpY(),CmpZ()) << endl;
      return 0;
    }
#包括
使用名称空间std;
结构向量{intx,y,z;};
结构CmpX{
布尔运算符()
{返回lhs.x    #include <iostream>
    using namespace std;

    struct vec { int x,y,z; };

    struct CmpX {
      bool operator() (const vec& lhs, const vec& rhs) const 
      { return lhs.x < rhs.x; }
    };

    struct CmpY {
      bool operator() (const vec& lhs, const vec& rhs) const 
      { return lhs.y < rhs.y; }
    };

    struct CmpZ {
      bool operator() (const vec& lhs, const vec& rhs) const 
      { return lhs.z < rhs.z; }
    };

    template <typename T>
    bool chained(const T &, const T &) {
      return false;
    }

    template <typename CMP, typename T, typename ...P>
    bool chained(const T &t1, const T &t2, const CMP &c, P...p) {
      if (c(t1,t2)) { return true;          }
      if (c(t2,t1)) { return false;         }
      else          { return chained(t1, t2, p...); }
    }

    int main(int argc, char **argv) {
      vec x = { 1,2,3 }, y = { 2,2,3 }, z = { 1,3,3 };
      cout << chained(x,x,CmpX(),CmpY(),CmpZ()) << endl;
      return 0;
    }