Попытка (немного) обобщить шаблон C ++.Ключ ассоциативного контейнера: инверсия значения - PullRequest
0 голосов
/ 28 сентября 2018

Цель шаблона функции ниже - взять любой unordered_map и создать новый unordered_map с инвертированными key_type и mapped_type.Функция ниже работает для std::unorderd_map.Я хотел бы, чтобы он работал дополнительно для EITHER std::unordered_map и любого аналога sth hashmap.

Дополнительное преимущество, которое я хотел бы сохранить, заключается в том, что при вызове функции, если требуется поведение по умолчанию, auto inversion = InvertHashMap(someIntStringMap) работает без аргументов шаблона.Тем не менее, если я предоставлю действительные исходные аргументы шаблона, я могу переопределить хеш-код по умолчанию, например, используемый для построения инвертированной карты.

У меня возникли серьезные трудности с созданием контейнера общего назначения, хотя я по-прежнему предоставляю шаблон по умолчаниюаргументы, основанные на 5 шаблонных аргументах этого контейнера.Как только я сделаю сам контейнер аргументом шаблона, произойдет сбой разрешения перегрузки и не удастся выполнить компиляцию.

Я развлекался, делая ассоциативный контейнер единственным аргументом шаблона, но затем возможность влиять на аргументы шаблона выходного контейнерапотеряны, по крайней мере, в том смысле, в каком они могут быть явно заданы в моем негибком примере.

#include <unordered_map>
#include <utility>
#include <functional>
#include <memory>

template <typename  InKeyType,
    typename  InValueType,
    typename  InHasher,
    typename  InEq,
    typename  InAlloc,
    typename  OutHash = std::hash<InValueType>,
    typename  OutEq = std::equal_to<InValueType>,
    typename OutAlloc=std::allocator<std::pair<constInValueType,InKeyType>>>

    std::unordered_map<InValueType, InKeyType, OutHash, OutEq, OutAlloc>
     InvertMap(const std::unordered_map<InKeyType, InValueType, InHasher, InEq, InAlloc>& source)
{
    std::unordered_map<InValueType, InKeyType, OutHash, OutEq, OutAlloc> outMap;
    for (const auto& sourceKVPair : source)
        outMap[std::get<1>(sourceKVPair)] = std::get<0>(sourceKVPair);

    return outMap;
}
//in a .cpp
unordered_map<int,string> um;
auto newUM = InvertHashMap(um);   //works well; newUM::key_type is string

Я хотел бы иметь возможность звонить InvertMap(aIntStringUnorderedMap) и ТАКЖЕ InvertMap< int, string, hash<int>, ..., MyCustomStringHasher>(aIntStringHashMapLikeClass)//producing a HashMapLikeClass<string,int, MyCustomStringHasher,...defaults>

TLDR: Как ввести аргументированный контейнер в шаблон, а также в параметры его шаблона без изменения семантики сайта вызова?

Редактировать.Это моя попытка использовать контейнер в качестве единственного аргумента шаблона.

template <typename AssocCont>
auto InvertCompliantHashMapThatIsntSTDUnorderedMap(const AssocCont&)
{
    typedef typename AssocCont::key_type InKeyType;
    typedef typename AssocCont::mapped_type InMappedType;
    typedef typename AssocCont::value_type InPairConstruct;
    typedef typename AssocCont::hasher InHasher;
    typedef typename AssocCont::key_equal InEq;
    //...
}
//But now there is no external means of desginating the new container's hasher,equality functor etc...
//And as it turns out, I cant even instantiate a new return object from AssocCont<InKeyType,InMappedType> since it is a distinct and unknown type
AssocCont<InMappedType,InKeyType> outmap = AssocCont<InMappedType,InKeyType>(); // nope. equivalent to object<key,value><otherkey,othervalue>()

ДВОЙНОЕ РЕДАКТИРОВАНИЕ: в спешке, чтобы привести пример, я выбрал std::map в качестве альтернативного примера параметра, который, как я понимаю, не делает 'У меня нет ни хэша, ни пяти аргументов шаблона.Таким образом, основа моего вопроса все еще пытается диверсифицировать эту функцию, но специально для аргументов, которые имеют пять собственных шаблонных аргументов с совместимым поведением ... .Я отредактировал свой пост, чтобы смягчить этот недосмотр.

1 Ответ

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

Мне кажется, что это может быть лучше реализовано способом, аналогичным стандартной библиотеке алгоритмов .Другими словами, спроектируйте свою функцию инверсии так, чтобы она содержала ряд итераторов во входном контейнере и итератор в выходном контейнере.Это будет проще в реализации и обеспечит большую гибкость для пользователей.Кроме того, он будет несколько независим от типа контейнера, если итераторы ввода и вывода удовлетворяют определенным условиям (возможно, навязанным понятиями ).Вот пример, который может быть не совсем тем, что вы хотите, но вы можете изменить его под свои нужды:

#include <algorithm>
#include <iostream>
#include <map>
#include <string>
#include <unordered_map>

namespace
{
    template <class InputIt, class OutputIt>
    void inverse_map(InputIt start, InputIt stop, OutputIt d_first)
    {
        while(start != stop) 
        {
            *d_first = {start->second, start->first} ;
            ++d_first ;
            ++start ;
        }
    }
} // anonymous namespace

int main()
{
    std::map<int, std::string> map_1 {{1, "foo"}, {2, "bar"}, {3, "foo"}} ;
    std::unordered_map<std::string, int> map_2 ;
    // 
    // Or, you can use:
    // 
    // std::unordered_map<std::string, int, MyCustomHasher> map_2 ;
    // 

    inverse_map(map_1.begin(), map_1.end(), std::inserter(map_2, map_2.end())) ;

    for(const auto& [key, value]: map_2) // requires C++17
        std::cout << key << ": " << value << "\n" ;

    return 0;
}

Вывод:

bar: 2
foo: 1

Попробуйте это онлайн здесь .

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