Как улучшить мою функцию векторного поиска? - PullRequest
1 голос
/ 23 марта 2019

Итак, я реализовал TCP-сервер на c ++ и хранил всех пользователей в векторе.Теперь мне нужна более обобщенная функция для поиска нескольких различных свойств. Как мне улучшить этот код?

struct client {
    std::string ip_address = "";
    int socket_id = 0;
    bool blocking = false;
};

enum client_codes {
    ip_address,
    socket_id,
    blocking,
};

template<typename T>
std::vector<client>::iterator search_vector(std::vector<client> &list, int type, T query) {

    std::vector<std::function<bool(client)>> comparators;

    comparators.push_back([&](client ob) {return ob.ip_address == std::to_string(query); });
    comparators.push_back([&](client ob) {return ob.socket_id == query; });
    comparators.push_back([&](client ob) {return ob.blocking == query; });

    return std::find_if(std::begin(list), std::end(list), [&](client obj) {return comparators[type](obj); });

}

// Implementation
std::vector<client> client_list;
auto search1(search_vector(client_list, socket_id, 321));
auto search2(search_vector(client_list, blocking, true));
auto search3(search_vector(client_list, ip_address, "192.168.0.85"));

Ответы [ 2 ]

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

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

struct client {
    std::string ip_address = "";
    int socket_id = 0;
    bool blocking = false;
};

// search_vector accepts a pointer to member of type T, and a value of type T
template<typename T>
std::vector<client>::iterator search_vector(std::vector<client>& list, T client::*member, T value){
    return std::find_if(list.begin(), list.end(), [value, member](const client& c){ return c.*member == value; });
}

Это то, как вы бы сейчас его использовали, без какой-либо дополнительной enums или специальной логики.

auto it1 = search_vector(client_list, &client::socket_id, 321);
auto it2 = search_vector(client_list, &client::blocking, true);
auto it3 = search_vector(client_list, &client::ip_address, "192.168.0.85");

Это точно search_vector функция, конечно, ограничена переменными-членами и тестами на точное равенство.Но было бы довольно просто расширить это с помощью указателей на функции-члены для таких функций, как get_ip_address().

Для большей общности, перегрузка с чем-то вроде std::function<bool(T)> condition вместо T value также может помочь вам сделать большеконкретные поиски, когда вы не хотите точного равенства.

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

Вот несколько предложений:

  1. Предполагается, что вы ищете клиентский вектор несколько раз - вместо использования std::find_if, сортируйте свой вектор и выполняйте двоичный поиск (например, используя ).std::equal_range).Если вы часто добавляете новых клиентов, рассмотрите возможность использования дополнительного небольшого несортированного буфера недавно добавленных клиентов и иногда объединяйте их в один отсортированный вектор.
  2. Не размещайте код, который проверяет тип поискавнутри предиката - таким образом он запускается снова и снова;и вам также нужен вектор компараторов на основе кучи - тьфу!... вместо этого шаблон вашей функции поиска по типу поиска, и пусть он использует один компаратор.Используйте функцию-обертку, которая выбирает соответствующую функцию поиска.
...