sort не работает с std::bind

360
18 февраля 2017, 06:18

Почему код не работает, если вместо 3 вставить число меньше 6. И как это можно исправить? Код должен сортировать вектор с помощью функтора std::greater, который должен применять 1 параметр. Сделать это нужно с помощью std::bind.

#include <set>
#include <algorithm>
#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <iterator>
#include <string>
#include <functional>
using namespace std;
template<typename T>
static void PrintVector(const std::vector<T> &v)
{
    for (auto iterator = v.begin(); iterator != v.end(); ++iterator)
    {
        std::cout << *iterator << " ";
    }
    std::cout << std::endl;
}
int main()
{       
    vector<int> v = { 1, 8, 7, 4, 3, 6, 2, 5 };
    PrintVector(v);
    auto greater_binded = bind(greater<int>(), placeholders::_1, 3);
    sort(v.begin(), v.end(), greater_binded);
    PrintVector(v);
    return 0;
}
Answer 1

Алгоритм std::sort предполагает наличие strict weak ordering для функций сравнения (25.4 Sorting and related operations)

3 For all algorithms that take Compare, there is a version that uses operator< instead. That is, comp(*i, *j) != false defaults to *i < *j != false. For algorithms other than those described in 25.4.3 to work correctly, comp has to induce a strict weak ordering on the values.

Это значит, что не допускается, что если comp( a, b ) есть true, то одновременно и comp( b, a ) также true.

Если вы хотите разбить массив на партиции, то используйте стандартный алгоритм std::partition. Например,

std::partition( v.begin(), v.end(), greater_binded );

Если необходимо, то затем каждую партицию можно отсортировать отдельно.

Answer 2

А что этот код должен делать? std::sort принимает бинарный предикат. Что-то с чем можно сделать так:

if(pred(x, y)){
   //...
}

Вы же взяли бинарный предикат greater и забиндили у него один аргумент. По идее теперь он принимает только один аргумент. Хотя на самом деле не специфицировано что там возвращает std::bind(пример)

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

В этом легко убедится, если заменить std::bind на старый добрый std::bind2nd. Ошибка выполнения сразу превратится в ошибку компиляции:

#include <algorithm>
#include <iostream>
#include <vector>
#include <functional>
using namespace std;
template<typename T>
static void PrintVector(const std::vector<T> &v)
{
    for (auto iterator = v.begin(); iterator != v.end(); ++iterator)
    {
        std::cout << *iterator << " ";
    }
    std::cout << std::endl;
}
int main()
{       
    vector<int> v = { 1, 8, 7, 4, 3, 6, 2, 5 };
    PrintVector(v);
    auto greater_binded = bind2nd(greater<int>(), 3);
    sort(v.begin(), v.end(), greater_binded);
    PrintVector(v);
}

h:125:23: error: no matching function for call to object of type 'std::binder2nd >' { return bool(_M_comp(*__it1, *__it2)); }

READ ALSO
В каких случаях возникает потребность использования raw pointers в современном C++?

В каких случаях возникает потребность использования raw pointers в современном C++?

После появления новых возможностей в C++ таких как std::make_shared() и std::make_unique то возникает вопрос : А есть ли хоть один случай, когда действительно...

327
запрос на откат даты поста на сайте mysql

запрос на откат даты поста на сайте mysql

ЗдравствуйтеМожно ли сгенерировать sql запрос таким образом, чтобы все сообщения на форуме были датированы 2011 годом? Форум основан на mybb

332
Sql запрос поиска в дереве

Sql запрос поиска в дереве

Нужно составить sql запрос, с помощью которого можно узнать входит ли пользователь в ветку партнёров

382
left-right join

left-right join

Сделал тройной left/right join, чтобы вывести в трех колонках результаты трех запросов

372