Использование собственного компаратора для std :: set с пользовательским конструктором - PullRequest
1 голос
/ 25 марта 2019

Допустим, у меня есть класс

class Custom
{
public:
    Custom (int x, int y) : x (x), y (x) {} 
    bool operator() (int a, int b)
    {
        return a < x && y < b;
    }
private:
    int x, y;
};

И я хочу набор, который

std::set<int, Custom> s 

с пользовательским конструктором Custom (т.е. Custom (1, 2))

Как мне этого добиться?

Кроме того, если я хочу использовать это в unordered_map, например,

std::unordered_map<string, std::set<int, Custom>> ht

как я могу это сделать?

Ответы [ 2 ]

1 голос
/ 25 марта 2019

Изготовление набора

Вам необходимо предоставить компаратор при создании набора:

using std::unordered_map;
using std::set; 
using std::string; 

set<int, Custom> s(Custom(10, 20)); 
// Or: 
auto s = set<int, Custom>(Custom(10, 20)); 

Это потому, что он должен иметь компаратор, как только вы начнете присваивать элементы набору, и так как ваш компаратор имеет параметры, он должен знать, что это такое

Использование набора на карте

Компаратор должен быть конструируемым по умолчанию, потому что вызов map["key"] создаст элемент по умолчанию, если он не существует:

class Custom
{
   public:
    // Add a default constructor
    Custom() : x(0), y(0) {}
    Custom (int x, int y) : x (x), y (x) {} 
    bool operator() (int a, int b)
    {
        return a < x && y < b;
    }
   private:
    int x, y;
};

В этом случае можно предоставить конструктор по умолчанию для конструктора по умолчанию, поскольку мы можем переназначить его:

unordered_map<string, set<int, Custom>> map; 
map["some key"] = set<int, Custom>(Custom(10, 20)); 

Что если у меня нет или не может быть конструктор по умолчанию?

Мы все еще можем использовать unordered_map, но мы должны использовать map.at("key") и map.emplace("key", value) вместо map["key"]:

unordered_map<string, set<int, Custom>> map; 
set<int, Custom> s(Custom(10, 20)); 
set<int, Custom> s2(Cunstom(30, 40)); 
s2.insert(1);
s2.insert(2); 
s2.insert(3); // put some stuff in the set

map.emplace("Hello", s); //Inserts the set

map.insert({"Hello", s2}); //Inserts the set as a key-value pair

Мы можем получить значения, используя map.at:

// This line gets the set at "Hello", and inserts 10 into the set:
map.at("Hello").insert(10); 
// If "Hello" isn't in the map, there's an error

И мы можем проверить, есть ли что-то на карте, используя map.find("key"):

// Get an iterator to the key value pair held by "Hello" in the map:
// An iterator acts like a pointer
auto iterator = map.find("Hello"); 

if(iterator == map.end()) // Check if we found the thing
{
    std::cout << "Couldn't find 'Hello' in the map"; 
} 
else 
{
    // Get the key from the iterator
    string key = iterator->first; 
    // Get a reference to the value from the iterator
    set<int, Custom>& value = iterator->second; 

}
0 голосов
/ 25 марта 2019

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

std::set<int, Custom> set_instance{ Custom{4,4} };

Этот экземпляр std::set использует Custom{4,4} в качестве компаратора.Различные экземпляры этого набора могут использовать разные компараторы.

Поскольку этот std::set не имеет конструктора по умолчанию, вы не можете использовать оператор [] карты, поэтому вам придется немного поработать.[] попытается создать экземпляр класса значения по умолчанию, и в этом наборе больше не будет используемого конструктора по умолчанию;поэтому вам нужно будет использовать find() или insert() для явного поиска и / или вставки новых значений в карту.C ++ 17 добавляет метод insert_or_assign(), который немного облегчает эту задачу.

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