首页 > 解决方案 > 尝试(稍微)概括 C++ 模板。关联容器 Key:Value Inversion

问题描述

下面的函数模板的目标是使用 any并用 the和倒置unordered_map生成一个新的。下面的功能适用于. 我希望它另外适用于 EITHER和任何 stl hashmap 模拟。unordered_mapkey_typemapped_typestd::unorderd_mapstd::unordered_map

我想维护的另一个好处是,在调用函数时,如果需要默认行为,则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一个备用参数示例,我意识到它没有哈希器,也没有五个模板参数。所以我的问题的基础仍然是试图使这个函数多样化,但特别是对于那些有五个自己的模板参数并且行为兼容的参数...... 我已经编辑了我的帖子以减轻这种疏忽。

标签: c++templatesrefactoring

解决方案


我觉得这可能以类似于标准算法库的方式更好地实现。换句话说,设计您的反转函数以将一系列迭代器放入输入容器,并将一个迭代器放入输出容器。它将更易于实施并为用户提供更大的灵活性。此外,只要输入和输出迭代器满足某些条件(可能由概念强加),它将在某种程度上独立于容器类型。这是一个示例,它可能不是您想要的,但您可以修改它以满足您的需要:

#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

在这里在线试用。


推荐阅读