Comparator 将 M×N 转化成 M+N

来源:互联网 发布:淘宝身份认证 编辑:程序博客网 时间:2024/05/16 05:41

用C++写程序经常需要写一些很小的functor,最常见的例子就是 compare functor,排序的,查找的,自己每定义一个数据结构,就要定义一个 compare functor,甚至多个(对不同字段)。甚至,针对指针的,智能指针的……的compare,这件工作很繁琐,很容易使人厌倦。

举个例子,同一个数据结构有M个字段,这些字段有P种类型,还有有N种不同的访问方式(直接提取、通过指针、通过智能指针、甚至通过反序列化等等),要实现所有这些情况的查找/排序,就需要 M×N 个 compare functor 的定义!

从 boost::multi_index 中学到一点,将 KeyExtractor 和 Comparator 分离,这样,只需要写 P 个Comparator,M+N个KeyExtractor,一般情况下,甚至不需要写Comparator,因为字段类型大多是内建类型,Comparator是默认的。举个例子吧:

using namespace std;

using boost::shared_ptr;

//using boost::intrusive_ptr;

 

struct mydata

{

   int d1, d2, d3, d4, d5;

   string s1, s2, s3;

};

 

struct mydata_get_int

{

   int offset;

 

   mydata_get_int(int offset) : offset(offset) {}

 

   int operator()(const mydata& x) const

   {

      return *(int*)(offset + (unsigned char*)&x);

   }

   // 假定T 就是mydata* 或者智能指针

   template<class T>

   int operator()(const T& x) const

   {

      return *(int*)(offset + (unsigned char*)&(*x));

   }

};

struct mydata_get_str

{

   int offset;

 

   mydata_get_str(int offset) : offset(offset) {}

 

   const string& operator()(const mydata& x) const

   {

      return *(string*)(offset + (unsigned char*)&x);

   }

   // 假定T 就是mydata* 或者智能指针

   template<class T>

   const string& operator()(const T& x) const

   {

      return *(string*)(offset + (unsigned char*)&(*x));

   }

};

 

 

 

class ExtractCompare

{

   KeyExtractor m_extractor;

   KeyCompare   m_comp;

 

public:

   ExtractCompare(const KeyExtractor& ext = KeyExtractor(),

                const KeyCompare& comp = KeyCompare())

      : m_extractor(ext), m_comp(comp) {}

 

   template<class T1, class T2>

   bool operator()(const T1& t1, const T2& t2) const

   {

      return m_comp(m_extractor(t1), m_extractor(t2));

   }

};

template<class KeyExtractor, class KeyCompare>
ExtractCompare<KeyExtractor, KeyCompare>
make_ec(const KeyExtractor& kex, const KeyCompare& comp)
{
   return ExtractCompare<KeyExtractor, KeyCompare>(kex, comp);
}
 

 

int main(int argc, char* argv[])

{

   vector<mydata> v1;

   vector<mydata*> v2;

   vector<shared_ptr<mydata> > v3;

   //vector<intrusive_ptr<mydata> > v4;

 

   // .... fill some data to v1, v2, v3

 

   sort(v1.begin(), v1.end(), make_ec(mydata_get_int(FIELD_OFFSET(mydata, d1)), less<int>()));

   sort(v2.begin(), v2.end(), make_ec(mydata_get_int(FIELD_OFFSET(mydata, d2)), less<int>()));

   sort(v1.begin(), v1.end(), make_ec(mydata_get_int(FIELD_OFFSET(mydata, d3)), less<int>()));

  

   sort(v3.begin(), v3.end(), make_ec(mydata_get_str(FIELD_OFFSET(mydata, s3)), less<string>()));

 

   return 0;

}

 

其中的ExtractCompare和make_ec可以作为公用代码,在多个程序中使用。

使用FIELD_OFFSET,在不降低效率的前提下,避免了代码膨胀。当然,这个例子中因为vector元素类型不同,会生成sort的3个不同版本,但是,如果不使用FIELD_OFFSET,而是直接再写一个extractor,这里会生成sort的4个版本。当然,一般情况下,不会像这样同时使用三个不同类型的vector。

C++0X 问世以后,其中的closure功能或许会使得这种方法显得过时,但是在没有closure的当前编译器上,这种方法还是很实用的。

原创粉丝点击