【问题标题】:Template function to receive a generic map as a parameter接收通用地图作为参数的模板函数
【发布时间】:2017-08-09 21:48:29
【问题描述】:

在很多情况下,我们希望对完全相同的std::mapstd::unordered_map 执行一些操作,而与映射的类型无关。让我们考虑以下示例:

#include <map>
#include <unordered_map>
#include <iostream>

template< template <typename,typename> class Container >
void printMap(Container<int, long> inputMap, bool additionalParam = false)
{
    for (const pair<int,long> p : inputMap)
        cout<<p.first <<","<< p.second <<std::endl;
}

int main()
{
int a = 1;
long b = 2;
map<int,long> map1;
map1.emplace(a,b);
unordered_map<int,long> map2;
map2.emplace(a,b);
printMap(map1);
printMap(map2);

return EXIT_SUCCESS;
}

如果我尝试编译上面的示例,我有这个:

error: no matching function for call to ‘printMap(std::map<int, long int>&)’

我在post 中读到了关于模板模板的使用。这样做的正确方法是什么?

【问题讨论】:

  • 一个std::map 有两个以上的模板参数。您还有一个类型 Compare 和一个类型 Allocator。您必须指定所有,甚至是默认的。
  • 请注意,您的代码将在 C++17 中正常工作;以下解决方案均适用于C++14及以下。

标签: c++ c++11 templates stdmap template-templates


【解决方案1】:

试试

template< template <typename...> class Container, typename ... Ts >
void printMap(Container<int, long, Ts...> inputMap,
              bool additionalParam = false)

代码中的(更大的)问题是std::mapstd::unordered_map 是具有四个(不是两个)模板参数的模板类。第 3 和第 4 具有默认值,因此您可以将 std::map 对象定义为

 std::map<int, long> map1;

但是,使用默认参数,您将其定义为

 std::map<int, long, std::less<int>,
          std::allocator<std::pair<const int, long> >> map1;

(ps:或者你可以让它变得简单并使用auto,就像在Semyon Burov的解决方案中一样;+1)

【讨论】:

    【解决方案2】:

    如果您以这种方式定义模板参数,编译器将无法推断出模板参数。 尝试使用:

    template<typename Map>
    void printMap(const Map& map, bool additionalParam = false) {
        for (const auto& p : map)
            cout<<p.first <<","<< p.second <<std::endl;
    }
    

    如果您需要检查,Map 是否正是 Map&lt;int, long int&gt;,然后将静态断言添加到函数体:

    static_assert( std::is_same< typename Map::key_type, int >::value &&
                           std::is_same< typename Map::mapped_type, long >::value, "!");
    

    【讨论】:

    • 我添加了一个static_assert 来维护类型约束。
    • @HenriMenke 就个人而言,我认为打印任何类型的地图而不是Map&lt;int, long int&gt; 的能力没有任何问题。
    • 我也不是,但问题的一部分是该地图专门用于 intlong
    • 差别不大,但 Henri Menke 提出的测试也可用于启用/禁用(通过 SFINAE)该功能;类似template &lt;typename Map&gt; typename std::enable_if&lt;std::is_same&lt; typename Map::key_type, int &gt;::value &amp;&amp; std::is_same&lt; typename Map::mapped_type, long &gt;::value&gt;::type printMap(const Map&amp; map, bool additionalParam = false)
    • 来吧...即使映射的一种键和值对于主题启动器是有价值的,断言绝对不应该在打印功能中。可能在其他地方,那里有地图元素的实际工作。 printMap 功能仅受限于映射的键和值类型存在 operator&lt;&lt; 重载
    【解决方案3】:

    试试这个:

    template<class Container>
    void printMap(const Container& inputMap)
    {
        using Key = typename Container::key_type; 
        using Value = typename Container::mapped_type;
        for (const std::pair<Key,Value> p : inputMap)
            std::cout << p.first << "," << p.second << std::endl;
    }
    

    或者更好,只是:

    template<class Container>
    void printMap(const Container& inputMap)
    {
        for (const auto& p : inputMap)
            std::cout << p.first << ","<< p.second << std::endl;
    }
    

    【讨论】:

    • @EdgarRokyan:哦,是的,没关系,我只是在说明这一点。但是,是的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-29
    • 2021-03-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多