Пользовательский компаратор для набора без перегрузки operator(), std::less, std::great

Я хочу собственный компаратор для следующего кода. Однако я не могу перегрузить operator(), std::less, std:: more. Я пытался добиться этого, используя lambdas, но gcc не позволяет мне использовать auto как нестатический член. Есть ли другой способ заставить это работать?

#include <iostream>
#include <map>
#include <set>

class Test {
  public:

    // bool operator () (const int lhs, const int rhs) {
    //     return lhs > rhs;
    // };


    using list = std::multiset<int  /*, Test*/>;
    std::map<const char*, list> scripts;
};

int main() {
  Test t;

  t.scripts["Linux"].insert(5);
  t.scripts["Linux"].insert(8);
  t.scripts["Linux"].insert(0);

  for(auto a: t.scripts["Linux"]) {
    std::cout << a << std::endl;
  }

    std::cout << "end";
}

Изменить: с лямбдами

class Test {
  public:
    auto compare = [] (const int a, const int b) { return a < b;}
    using list = std::multiset<int, compare>;    //here
    std::map<const char*, list> scripts;
};

Ошибка:'auto' not allowed in non-static class member auto compare = [] (const int a, const int b) { return a < b;}

3 ответа

Я хочу собственный компаратор для следующего кода. Однако я не могу перегрузить operator(), std::less, std::greater,

Я предполагаю, что вы не можете перегружать operator() из Test, но может быть и другого класса. Если это так, создайте внутренний private функтор, который перегружает operator() и это может быть частью псевдонима using list = std::multiset<int, Compare>;

class Test
{
private:
    struct Compare
    {
        bool operator()(const int lhs, const int rhs) const /* noexcept */ { return lhs > rhs; }
    };

public:
    using list = std::multiset<int, Compare>;
    std::map<std::string, list> scripts;
};

Существует проблема с вашим подходом, даже если вы можете определить лямбду так, как вы хотите. Посмотрите на multiset декларация:

template<
    class Key,
    class Compare = std::less<Key>,
    class Allocator = std::allocator<Key>
> class multiset;

Обратите внимание, что каждый параметр шаблона является типом (используя class ключевое слово). Теперь посмотрим, как вы пытались определить свой список:

using list = std::multiset<int, compare>;
                            ^      ^
                          type   value

Первый параметр хорош, но второй - несоответствие. Compare Параметр должен быть типом, а не объектом. Одним из общих способов разрешения такой ситуации является замена compare с decltype(compare), но это, кажется, не то, что вы хотите (плюс это проблематично для лямбда-типов). Вы, кажется, хотите построить по умолчанию list использовать compare вместо просто созданного по умолчанию объекта того же типа.

Итак, что вам нужно, это класс, чей конструированный объект по умолчанию реализует operator() таким образом, что дает порядок, который вы хотите. Поскольку мы имеем дело с intстандартная библиотека имеет несколько готовых типов для этой цели, а именно std::less а также std::greater,

using list = std::multiset<int, std::greater<int>>;

Однако я не могу перегрузить operator(), std::less, std:: more.

Хм... это говорит о том, что пример кода, возможно, был слишком упрощен, поскольку перегрузка не требуется. Хорошо, давайте предположим, что список имеет некоторый тип, с которым сложнее работать, скажем:

class I { /* Internals not important for this example. */ };
using list = std::multiset<I, ???>;

Если вам разрешено изменять Iтогда самым простым подходом может быть определение operator> (или же operator<) для объектов типа I, поскольку std::greater (или же std::less) используя этот оператор, вы получаете нужный заказ из стандартного шаблона, не перегружая его.

Если вам не разрешено изменять Iтогда я думаю, что у вас осталось написать свой собственный функциональный объект, так как это одна из ситуаций, когда лямбда неадекватна. К счастью, классы, реализующие функциональные объекты, легко написать; Лямбды вытеснили их в других ситуациях главным образом потому, что лямбда-синтаксис имеет тенденцию быть более удобным.

struct CompareI {
    bool operator() (const I & lhs, const I & rhs) const { return /* fill this in */; }
};
using list = std::multiset<I, CompareI>;

Хотя это определяет operator()Это не перегрузка. Так что он должен удовлетворять предъявляемым вам требованиям.

Вы можете использовать указатель на функцию сравнения в конструкторе:

main.cpp

#include <iostream>
#include <set>

using compType=bool(*)(int lhs, int rhs);

bool custom_compare_function(int lhs, int rhs)
{
    return lhs>rhs;
}


using list = std::multiset<int,compType>;
int main() {
    list l(&custom_compare_function);
    l.insert(1);
    l.insert(4);
    l.insert(2);
    for (auto& item: l) std::cout<<item<<std::endl;
}

производит вывод

$ g++ main.cpp 
$ ./a.out 
4
2
1
Другие вопросы по тегам