лямбда-компаратор для `std :: set_intersection` - PullRequest
0 голосов
/ 12 сентября 2018

Следующий код выдает ошибку компиляции

class A
{
public:
    A(int i):a(i){}
    int a;
};


int main()
{
  std::vector<A> As;
  As.push_back(A(1));
  As.push_back(A(2));
  As.push_back(A(3));
  As.push_back(A(4));
  As.push_back(A(5));

  std::vector<int> Is = {2,4};
  std::vector<int> Bs = {1,2,3,4,5};

  std::vector<A> intersection;

  std::set_intersection
  (
    As.begin(), As.end(),
    Is.begin(), Is.end(),
    std::back_inserter(intersection),
    [](int const& lhs, A const& rhs)
    {
        return lhs < rhs.a;
    }
  );
}

ошибка: нет соответствующей функции для вызова объекта типа '(лямбда в c.cpp: 33: 4)' if (__comp (* __ first1, * __ first2))

Мне не удалось реализовать лямбда-функцию для компаратора этого std::set_intersection. Я также пытался перегрузить operator>, operator< и operator== в классе A, но все равно не получилось. Вы можете мне помочь?

Ответы [ 2 ]

0 голосов
/ 12 сентября 2018

После предложения @Klaus использовать функционор, вот рабочий пример использования функционора.

class A
{
public:
    A(int i):a(i){}
    int a;
};

class comparatorsForSetIntersection
{
public:
    bool operator()(int lhs, A rhs) {return lhs + rhs.a;}
    bool operator()(A lhs, int rhs) {return lhs.a + rhs;}
};

int main()
{
  std::vector<A> As;
  As.push_back(A(1));
  As.push_back(A(2));
  As.push_back(A(3));
  As.push_back(A(4));
  As.push_back(A(5));

  std::vector<int> Is = {2,4};
  std::vector<int> Bs = {1,2,3,4,5};

  std::vector<A> intersection;

  comparatorsForSetIntersection comps;
  std::set_intersection
  (
    As.begin(), As.end(),
    Is.begin(), Is.end(),
    std::back_inserter(intersection),
    comps
  );
}
0 голосов
/ 12 сентября 2018

Проблема здесь в том, что функция сравнения вызывается в обоих направлениях, один раз с (A, int) и один раз с (int, A).Я не проверял реализацию, возможно, ожидается, что оба типа одинаковы.

В качестве решения вы можете просто предоставить обе подписи:

class A
{
    public:
        A(int i):a(i){}
        int a;
};

// Helper to get Lambda with multiple signatures in place 
// template deduction guide is a C++17 feature! 
template<class... Ts> struct funcs : Ts... { using Ts::operator()...; };
template<class... Ts> funcs(Ts...) -> funcs<Ts...>;

// if c++17 is not available, you have to write a functor/function
// with both signatures 

int main()
{
    std::vector<A> As;
    As.push_back(A(1)); 
    As.push_back(A(2));
    As.push_back(A(3));
    As.push_back(A(4));
    As.push_back(A(5));

    std::vector<int> Is = {2,4};
    std::vector<int> Bs = {1,2,3,4,5};

    std::vector<A> intersection;

    std::set_intersection
        (
            As.begin(), As.end(),
            Is.begin(), Is.end(),
            std::back_inserter(intersection),
            funcs{
                [](A const& lhs, int const& rhs)
                {
                    return lhs.a < rhs;
                },
                [](int const& lhs, A const& rhs)
                {
                    return lhs < rhs.a;
                }
            }
        );
}

Я запускаю это под g ++ (GCC) 8.1.1 20180712 (Red Hat 8.1.1-5) на Fedora.Если я предоставлю только одну подпись, независимо от использования int или A, я получу ошибку:

1)

no match for call to '(main()::<lambda(const A&, const int&)>) (int&, A&)'

или

2)

no match for call to '(main()::<lambda(const int&, const A&)>) (A&, int&)'

Таким образом, необходимо предоставить функцию comp, которая принимает обе подписи здесь.

...