Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 试图(稍微)推广C++;模板。关联容器键:值反转_C++_Templates_Refactoring - Fatal编程技术网

C++ 试图(稍微)推广C++;模板。关联容器键:值反转

C++ 试图(稍微)推广C++;模板。关联容器键:值反转,c++,templates,refactoring,C++,Templates,Refactoring,下面函数模板的目标是获取任何无序映射,并生成一个新的无序映射,其中键类型和映射类型倒置。 下面的函数适用于std::无序映射。我希望它能在std::unordered_-map和任何stl hashmap模拟中起到额外的作用 我想维护的另一个好处是,在调用函数时,如果需要默认行为,autoinversion=InvertHashMap(someIntStringMap)不使用模板参数。但是,如果我提供了有效的初始模板参数,我可以覆盖默认的哈希器,例如用于构建反转映射的哈希器 我很难使容器成为泛型

下面函数模板的目标是获取任何
无序映射
,并生成一个新的
无序映射
,其中
键类型
映射类型
倒置。 下面的函数适用于
std::无序映射
。我希望它能在
std::unordered_-map
和任何stl hashmap模拟中起到额外的作用

我想维护的另一个好处是,在调用函数时,如果需要默认行为,
autoinversion=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

双重编辑:在我急于提供一个示例的过程中,我选择了
std::map
作为另一个paramater示例,我意识到它既没有哈希器,也没有五个模板参数。因此,我的问题的基础仍然是尝试使此函数多样化,但是特别针对具有五个模板参数且行为兼容的参数…。我已经编辑了我的帖子,以减轻这种疏忽。

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

#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;
}

在线试用。

你能使用
std::map::key_type
std::map::mapped_type
(对于
std::unordered_map
)吗?@crayzeewulf如果我试过,但不幸的是,如果容器的模板参数不是模板定义的一部分,用户无法覆盖它们。如果默认的分配器、哈希器和相等函子都是必需的,那么容器是唯一的模板参数,使用作用域穿透来获取相关类型就可以了。我只想覆盖出站模板参数,但它们是基于输入的。我喜欢这个想法,但没有我脑子里想的那么多。
auto-IntStringMap=InvertMap(StringIntMap)的优雅不可发布。无需预先声明out容器,也无需对任何类型的迭代器进行参数化。事实证明,模板不是魔术实体,它使C++像动态语言,而牺牲了性能。我想我可以为我知道我想要的特定容器(比如我的示例)创建专门的版本,并为所有其他情况创建迭代器版本。当然,对于手头的特定容器和类型,总是可以选择手动编写流程。@schulmaster我明白你的意思。和你一样,我也尝试过实现基于容器的算法,因为它们显然很简单。然而,一次又一次地推广它们,导致了太多的复杂情况。在大多数情况下,我最终使用了基于范围的算法(比如标准库中的算法)。这是一些讨论。C++很快就会简化事物。在许多其他方面,使用基于迭代器的方法的一个优点是它将算法与容器解耦。因此,这些算法适用于现有/预期的容器以及未来/非预期的容器。如果您最终自行设计了一个支持迭代器的全新map类,那么基于迭代器的实现很可能在不做任何修改的情况下工作。然而,基于容器的方法很可能需要重写/重构。
#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