set_intersection с пользовательским набором компараторов - PullRequest
0 голосов
/ 28 января 2020

Когда я использую функцию std :: set_intersection с множеством, имеющим пользовательский компаратор, я не получаю ожидаемый результат. Следующий код выводит, что {5,9,7} пересекается с {9}, это пустой набор Однако, если я просто использую обычный компаратор, я получаю {9}.

#include <iostream>
#include <cstdlib>
#include <set>

using namespace std;
auto cmp = [](int* a, int* b) { return a < b; };
using stupid_set = set<int*, decltype(cmp)>;
int main() {
    int* n5 = new int(5);
    int* n9 = new int(9);
    int* n7 = new int(7);
    stupid_set s0 {n5, n9, n7};
    stupid_set s1 {n9};
    stupid_set i;
    for (auto s:s0) {
        cout << "s0:" << *s << endl;
    }
    for (auto s:s1) {
        cout << "s1:" << *s << endl;
    }
    set_intersection(s0.begin(), s0.end(), s1.begin(), s1.end(), std::inserter(i, i.begin()));
    for (auto x : i) {
        cout << "Int=" << *x << endl;
    }
}

Ответы [ 2 ]

2 голосов
/ 28 января 2020

Есть несколько проблем с вашим кодом, но основная заключается в том, что вы используете пользовательский компаратор для наборов, но не для вызова функции std::set_intersection. Эта функция также должна сравнивать элементы и, конечно, должна сравнивать их с одним и тем же компаратором.

Использование:

struct cmp 
{
  bool operator()(int* a, int* b) const { return *a < *b; };
};

using stupid_set = set<int*, cmp>;

и

set_intersection(
 s0.begin(), s0.end(),
 s1.begin(), s1.end(),
 std::inserter(i, i.begin()),
 cmp{}  // custom comparator used for sets
);

Всего живого демо здесь: https://godbolt.org/z/OAr3xV.


Обратите внимание, что если вы опустите компаратор, std::set_intersection будет использовать operator< для заданных элементов, и эта операция будет как правило, неопределено для указателей .

Если вы действительно хотите сравнивать указатели, а не целочисленные значения, на которые они указывают, вам нужно использовать std::less, так как это определяет порядок даже для указателей в целом:

struct cmp 
{
  bool operator()(int* a, int* b) const { return std::less<int*>{}(a, b); };
};

Опять же, вам нужно передать этот компаратор и std::set_intersection.

Демонстрационная версия: https://godbolt.org/z/tLdfqn.

0 голосов
/ 28 января 2020

Вы смешиваете функцию сравнения, переданную в std::set и std::set_intersection. При передаче в std::set, функция Compare используется для сортировки, потому что это функция сравнения ключей. При передаче на std::set_intersection оно используется для определения пересечения.

Попробуйте выполнить следующее:

#include <iostream>
#include <cstdlib>
#include <set>
#include <algorithm>

struct cmp {
   bool operator()(int *a, int *b) const {
      return *a < *b;
   }
};

using stupid_set = std::set<int*, cmp>;

int main() {
    int* n5 = new int(5);
    int* n9 = new int(9);
    int* n7 = new int(7);

    stupid_set s0 {n5, n9, n7};
    stupid_set s1 {n9};
    stupid_set i;

    for (auto s : s0) {
        std::cout << "s0:" << *s << std::endl;
    }

    for (auto s:s1) {
        std::cout << "s1:" << *s << std::endl;
    }

    std::set_intersection(
        s0.begin(),
        s0.end(),
        s1.begin(),
        s1.end(),
        std::inserter(i, i.begin()),
        cmp()
    );

    for (auto x : i) {
        std::cout << "Int=" << *x << std::endl;
    }
}

Проверка в реальном времени

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...