2016-12-12 3 views
0

Учитывая классСортировка списка общих указателей

class objects { 
    public: 
    bool compareArea (const objects& obj) const { return this->area < obj.area; } 
    private: 
    double area; 
}; 

Я хочу, чтобы отсортировать

list<shared_ptr<objects>> myObjects; 

Я не могу использовать лямбда (с поддержкой моего ToolChain в C++ 11 является неполным). Таким образом, я пробовал следующее:

using namespace placeholders; 
myObjects.sort(bind(&objects::compareArea,_1,_2)); 

Эта строка вызывается из другого файла (не из класса!). Проблема в том, что compareArea требует ввода двух objects. Но я даю два общих указателя на objects. Есть ли простой способ включения разыменования указателей вsort -call? Я хочу, чтобы функция objects::compareArea(..) оставалась такой, какой она есть. Я не хотят такого рода решения

bool compareArea (const shared_ptr<objects>& ptr1, const shared_ptr<objects>& ptr2) { 
    return ptr1->area > ptr2->area; 
} 

// in same source-file: 
myObjects.sort(bind(compareArea,_1,_2)); 

где compareArea не является членом-функцией objects. На самом деле, мое любимое решение было бы перегрузкой оператора <.

+0

Который '' bind' и placeholders' вы используете? Это может также оказать поддержку выражениям, которые вам нужны. – Angew

+1

Как насчет 'bool lessObject (const shared_ptr & lhs, const shared_ptr & rhs) {return lhs-> compareArea (* rhs); } '? – Jarod42

+0

@Angew Я не совсем понимаю ваш вопрос ... Я использую std :: bind, а заполнители - '_1' и '_2', как указано в фрагменте кода выше. – Kapa11

ответ

3

Я настоятельно рекомендую, что вы никогда не хранить любые вид указателя в контейнере.

Вместо этого создайте класс дескриптора, который поддерживает необходимые операторы арифметики и сравнения.

Это делает код, который легче рассуждать о:

class objects { 
public: 
    objects(double w, double h) : area(w * h) {} 

    bool operator<(const objects& r) const { return this->area < r.area; } 
private: 
    double area; 
}; 


struct object_handle 
{ 
    object_handle(shared_ptr<objects> const& ptr) : ptr_(ptr) {} 

    static object_handle create(double w, double h) { return make_shared<objects>(w,h); } 

    bool operator < (object_handle const& r) const { 
     return *ptr_ < *r.ptr_; 
    } 
    shared_ptr<objects> ptr_; 
}; 


int main() { 
    std::vector<object_handle> mylist; 
    mylist.push_back(object_handle::create(10, 7)); 
    mylist.push_back(object_handle::create(2, 5)); 
    std::sort(mylist.begin(), mylist.end()); 
} 
+0

Почему я не должен хранить указатели в контейнере?Часто я просто храню общие указатели в списках, где не запрашиваются арифметические операции над элементами. Где невыгодно делать это так, как я это делал раньше? – Kapa11

+2

, когда мы работаем с общими указателями, мы почти всегда хотим работать с тем, на что указывает указатель, а не с самим указателем. Поэтому имеет смысл отвлечь детали того, как объект хранится. Затем мы можем поговорить с интерфейсом дескриптора значимым образом (sort, +, -, less, do_something и т. Д.), Не беспокоясь о деталях того, как эта ссылка хранится. Если позже мы передумаем о реализации дескриптора (например, unique_ptrs или вообще не указатели), нам нужно только изменить код в одном месте. –

+0

Хорошо, ты убедил меня ... Я сделаю это в будущем. Но если мы хотим только разыменовать указатели в контейнере и не хотим делать какие-либо арифметические операции над ним, тогда такой дескриптор не будет лишний код (даже если гораздо проще расширить структуру данных). – Kapa11

2

Лямбда просто синтаксический сахар для класса с operator(), так что вы можете очень легко написать один непосредственно (особенно, если вам не нужны снимки):

struct Comparator 
{ 
    bool operator() (const shared_ptr<objects> &lhs, const shared_ptr<objects> &rhs) const 
    { 
    return lhs->compareArea(*rhs); 
    } 
}; 

myObjects.sort(Comparator()); 
+0

Это работает. Я также заменил функцию 'compareArea (..)' путем перегрузки '' 'оператора в' objects'. Поэтому я просто вернул '(* lhs)> (* rhs)'. – Kapa11