试图(略)概括C ++模板。关联容器的键:值倒置

时间:2018-09-28 06:11:27

标签: c++ templates refactoring

下面的函数模板的目标是采用unordered_mapunordered_map倒置的任何key_type并生成一个新的mapped_type。 以下功能适用于std::unorderd_map。我希望它可以额外用于EITHER std::unordered_map和任何stl 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)和ALSO 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 :(得分:1)

我觉得以类似于standard algorithms library的方式可以更好地实现这一点。换句话说,将反转函数设计为将一定范围的迭代器放入输入容器中,并将迭代器放入输出容器中。实施起来会更简单,并为用户提供更大的灵活性。此外,只要输入和输出迭代器满足某些条件(也许由concepts施加),它就在某种程度上与容器类型无关。这是一个可能并非您想要的示例,但您可以根据需要进行修改:

#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

在线here试用。