2013-08-24 5 views
2

Как создать один компаратор для сравнения в разных полях. Различные поля могут иметь разные типы (uint или string). Должен ли я использовать T *?Компаратор разных классов

Необходимо уменьшить длину кода.

template<typename T> 
class ComparatorSelector 
{ 
public: 
    struct CompareByLabel{ 
     bool operator() (const T & iRight, const T & iLeft) 
     { 
      return iRight->m_label > iLeft->m_label; 
     } 
    }; 
    struct CompareByHouseNumber{ 
     bool operator() (const T & iRight, const T & iLeft) 
     { 
      return iRight->m_houseNumber > iLeft->m_houseNumber; 
     } 
    }; 
    //... 
}; 


template< class T, class C, typename W > 
class SearchIndex 
{ 
public: 
    SearchIndex() {} 

    void Build(std::vector<T> iElems, C iComparator, std::ofstream oStream) 
    { 
     std::map< T *, size_t> numbersOfElems; 

     for(class std::vector<T>::iterator it = iElems.begin(); it != iElems.end(); ++it){ 
      m_elems.insert(&(*it)); 
      numbersOfElems[&(*it)] = m_elems.end - it ; 
     } 

     oStream << m_elems.size(); 
     for(class std::multiset< T * >::iterator it = m_elems.begin(); it!= m_elems.end(); ++it) 
      oStream << numbersOfElems[*it]; 

     m_compareMode = iComparator; 
    } 
//.... 
} 
+3

Скомпилирует ли этот код? pass ofstream по значению, iRight/iLeft являются ссылкой, но применяется указатель? – billz

+0

... um ... и компараторы возвращают «большее» состояние, а не «меньшее» (да, это * может быть целеустремленным, но что-то говорит мне ... нет – WhozCraig

+0

Да, мне нужно пройти поток по ссылке В компараторе мне нужно передать указатели на объекты, но вопрос не в этом. – YYY

ответ

2

Вы можете использовать указатели для пользователей, чтобы настроить объекты компаратора. Медленнее, но более простой подход заключается в следующем:

#include <iostream> 

template <typename Type, typename Class> 
class comparator 
{ 
    Type Class::*d_member; 
public: 
    comparator(Type Class::*member): d_member(member) {} 
    bool operator()(Class const& object0, Class const& object1) const { 
     return object0.*(this->d_member) < object1.*(this->d_member); 
    } 
}; 

template <typename Type, typename Class> 
comparator<Type, Class> 
make_comparator(Type Class::*member) 
{ 
    return comparator<Type, Class>(member); 
} 

int main() 
{ 
    typedef std::pair<int, double> pair; 
    pair p0(17, 3.14); 
    pair p1(42, 2.7); 
    std::cout << std::boolalpha 
       << "first: " << make_comparator(&pair::first)(p0, p1) << ' ' 
       << "second: " << make_comparator(&pair::second)(p0, p1) << ' ' 
       << '\n'; 
} 

Поскольку эта версия использует указатель на член во время выполнения, он не может быть легко встраивается и, таким образом, не так быстро, как вы, возможно, хотите его быть. Элемент также может быть встроен в создании типа компаратора как его использовать немного раздражает:

template <typename Type, typename Class, Type Class::*Member> 
class comparator 
{ 
public: 
    bool operator()(Class const& object0, Class const& object1) const { 
     return object0.*Member < object1.*Member; 
    } 
}; 

int main() 
{ 
    typedef std::pair<int, double> pair; 
    pair p0(17, 3.14); 
    pair p1(42, 2.7); 
    std::cout << std::boolalpha 
       << "first: " << comparator<int, pair, &pair::first>()(p0, p1) << ' ' 
       << "second: " << comparator<double, pair, &pair::second>()(p0, p1) << ' ' 
       << '\n'; 
} 
+0

Это именно то, что мне нужно. – YYY

0

Это пример из компаратора, который использует различные поля различных типов:

#include <set> 

using namespace std; 

class House { 
public: 
    string m_label; 
    int m_houseNumber; 
}; 

class HouseCompare { 
public: 
    bool operator()(const House& a, const House& b) 
    { 
     if (a.m_houseNumber>0 && b.m_houseNumber>0) 
      return a.m_houseNumber < b.m_houseNumber; 
     else if (a.m_houseNumber>0) 
      return false; 
     else if (b.m_houseNumber) 
      return true; 
     else 
      return a.m_label < b.m_label; 
    } 
}; 

int main(int argc, char *argv[]) 
{ 
    typedef multiset<House, HouseCompare> Houses; 

    Houses houses; 
    House house_data[] = { 
     {"foo", 1}, 
     {"foo1", 0}, 
     {"foo0", 0}, 
     {"foo", 2} 
    }; 
    houses.insert (house_data, house_data+sizeof(house_data)/sizeof(House)); 

    for (Houses::iterator i = houses.begin(); i != houses.end(); ++i) 
     cout << i->m_houseNumber << ": " << i->m_label << endl; 

    return 0; 
} 

Выход:

0: foo0 
0: foo1 
1: foo 
2: foo