Могу ли я использовать лямбда-выражение в качестве хэш-функции в хеш-подобном интерфейсе boost::multi_index?

Можно ли использовать лямбду для хеширования в хешированный_‹не›уникальный интерфейс для boost::multi_index? См. этот пример: https://godbolt.org/z/1voof3

Я также видел это: Как использовать лямбда-функцию как хэш-функция в unordered_map? где ответ говорит:

Вам нужно передать лямбда-объект в конструктор unordered_map, поскольку лямбда-типы не являются конструктивными по умолчанию.

и я не уверен, что это вообще возможно сделать для данного примера на godbolt.


person Daniel    schedule 23.12.2020    source источник
comment
Текущий стандарт C++ — это, конечно же, C++20, который позволяет создавать лямбда-выражения по умолчанию. То есть законно что-то вроде этого: std::unordered_set<int, decltype([](auto x){ return hash(x); })> s;   -  person Dietmar Kühl    schedule 24.12.2020


Ответы (2)


Начиная с C++20, да, вы можете: https://godbolt.org/z/fTbzPP (примечание f объявляется как auto const hash_f без &).

Что касается утверждения @sehe о том, что multi_index_containers нельзя передавать экземпляры хеш-объектов (или других промежуточных объектов-функций) во время построения, утверждение неверно: они могут, хотя интерфейс несколько сложен:

Демо-версия Coliru

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <functional>

struct non_default_ctble_hash
{
  non_default_ctble_hash(std::size_t n):n{n}{}
  
  template<typename T>
  std::size_t operator()(const T& x){return std::hash<T>{}(x)*n;}

  std::size_t n;
};

using namespace boost::multi_index;
using container=multi_index_container<
  int,
  indexed_by<
    hashed_unique<identity<int>,non_default_ctble_hash>
  >
>;

int main()
{
  container::ctor_args_list cal{
    {0,identity<int>{},non_default_ctble_hash{666},std::equal_to<int>{}}
  };
  
  container c(cal);
}
person Joaquín M López Muñoz    schedule 24.12.2020
comment
Спасибо за помощь. :) Я все еще пытаюсь демистифицировать ctor_args_list. Я не могу заставить его работать, используя tag вместо uint index в качестве первого аргумента: ссылка. - person Daniel; 24.12.2020
comment
Я неправильно прочитал документацию, в которой говорится, что она не поддерживается? (В качестве альтернативы, где это задокументировано?) - person sehe; 24.12.2020
comment
Индексы действительно нельзя построить сами по себе: можно получить ссылку на индекс только из ранее существовавшего multi_index_container. Документы для ctor_args_list: boost.org/libs/multi_index/doc/ учебник/ - person Joaquín M López Muñoz; 25.12.2020
comment
@Daniel 0, который вы видите в {0,identity<int>{},..., - это не номер индекса, а первый параметр конфигурации хешированных индексов (количество сегментов). Вы не можете указать, для каких индексов вы предоставляете объекты построения в ctor_args_list, но вместо этого вы должны предоставить столько кортежей, сколько индексов, в порядке их определения. - person Joaquín M López Muñoz; 25.12.2020

Я не думаю, что вы можете. Со стандартным контейнером вам пришлось бы предоставить фактический экземпляр конструктору. Однако MultiIndex этого не позволяет:

документы

Как поясняется в разделе концепций индекса индексы не имеют общедоступных конструкторов или деструкторов. Назначение, с другой стороны, предусмотрено. При построении max_load_factor() равен 1,0.

Лазейка?

Возможно, вы можете уйти с локально определенным классом:

auto const hash_f = [](int const& n) { return std::hash<int>()(n); };
struct HashType : decltype(hash_f) {};

using AnimalsMultiIndex = multi_index_container<
    Animal, indexed_by<hashed_non_unique<
                tag<animal_legs>, member<Animal, LegsType, &Animal::legs>,
                HashType>>>;

AnimalsMultiIndex animals;

Что работает: требуется c++20

#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/tag.hpp>
#include <boost/multi_index_container.hpp>
#include <iostream>
#include <string>

using namespace boost::multi_index;
using LegsType = int;

struct Animal {
    std::string name;
    LegsType legs;
};

// tags
struct animal_legs {};

int main() {
    // using lambda doesn't work for hashing
    auto const hash_f = [](int const& n) { return std::hash<int>()(n); };
    struct HashType : decltype(hash_f) {};

    using AnimalsMultiIndex = multi_index_container<
        Animal, indexed_by<hashed_non_unique<
                    tag<animal_legs>, member<Animal, LegsType, &Animal::legs>,
                    HashType>>>;

    AnimalsMultiIndex animals;

    animals.insert({ "cat", 4 });

    auto const& legs_index = animals.get<animal_legs>();
    int num_of_legs = 4;
    std::cout << "Number of animals that have " << num_of_legs
              << " legs is: " << legs_index.count(num_of_legs) << '\n';
}

Отпечатки

Number of animals that have 4 legs is: 1
person sehe    schedule 24.12.2020
comment
Я не знал о struct HashType : decltype(hash_f) {};. Спасибо :) - person Daniel; 24.12.2020