区分地图和集合的模板 [英] Template distinguishing between maps and sets

查看:29
本文介绍了区分地图和集合的模板的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

setunordered_setmapunordered_mapcommon代码>,我需要几个方法,其中处理实际上是不同的.我的问题是让编译器推断出要使用的实现.

In creating a code common for set, unordered_set, map, and unordered_map, I need the few methods, where the handling is actually different. My problem is getting the compiler to deduce, which implementation to use.

考虑示例:

#include <map>
#include <unordered_set>
#include <string>
#include <iostream>

using namespace std;

static unordered_set<string>    quiet;
static map<const string, const string>  noisy;

template <template <typename ...> class Set, typename K>
static void insert(Set<K> &store, const string &key, const string &)
{
    cout << __PRETTY_FUNCTION__ << "(" << key << ")\n";
    store.insert(key);
}

template <template <typename ...> class Map, typename K, typename V>
static void insert(Map<K, V> &store, const string &key, const string &v)
{
    cout << __PRETTY_FUNCTION__ << "(" << key << ", " << v << ")\n";
    store.insert(make_pair(key, v));
}

int
main(int, char **)
{
    insert(noisy, "cat", "meow");
    insert(quiet, "wallaby", ""); /* macropods have no vocal cords */

    return 0;
}

尽管 cat 行有效,但小袋鼠行会从编译器 (clang-10) 中触发以下错误:

Though the cat-line works, the wallaby-line triggers the following error from the compiler (clang-10):

t.cc:22:8: error: no matching member function for call to 'insert'
        store.insert(make_pair(key, v));
        ~~~~~~^~~~~~
t.cc:29:2: note: in instantiation of function template specialization
      'insert<unordered_set, std::__1::basic_string<char>, std::__1::hash<std::__1::basic_string<char> > >' requested here
        insert(quiet, "wallaby", ""); /* macropods have no vocal cords */

错误很明显,quiet,它是一个unordered_set,也被路由到map的插入实现——而不是为 unordered_set 制作的.

The error makes it obvious, the quiet, which is an unordered_set, is routed to the insert-implementation for map too -- instead of that made for the unordered_set.

现在,这并非完全没有希望——如果我:

Now, this is not entirely hopeless -- if I:

  1. 详细说明所有模板参数——包括可选参数(比较器、分配器等)
  1. Spell out all of the template-parameters -- including the optional ones (comparator, allocator, etc.)
template <template <typename ...> class Set, typename K, typename A, typename C>
static void insert(Set<K, A, C> &store, const string &key, const string &)
...
template <template <typename ...> class Map, typename K, typename V, typename A, typename C>
static void insert(Map<K, V, A, C> &store, const string &key, const string &v)

  • unordered_set 替换为 set.
  • Replace the unordered_set with set.
  • 程序将按预期编译和运行 -- 编译器将根据每个模板采用的参数数量(三个对四个)区分 setmap.

    The program will compile and work as expected -- the compiler will distinguish set from map by the number of arguments each template takes (three vs. four).

    但是 unordered_setmap 有相同数量的参数(四个)...而 unordered_map五个 参数,所以它不会被路由到地图处理方法...

    But unordered_set has the same number of arguments as map (four)... And unordered_map has five arguments, so it will not be routed to the map-handling method...

    如何为要处理的两种类型的集合收紧集合处理函数的声明?如何在同一代码中同时处理 mapunordered_map?

    How can I tighten the set-handling function's declaration for both types of sets to be handled by it? How can I handle both maps and unordered_maps in the same code?

    推荐答案

    首先,实际的解决方案,适用于当前在野外发现的编译器版本——用 gcc-4.4 测试.7(RedHat6 上的标准编译器)、gcc-8.3.1 和 clang-10 是:

    First of all, the actual solution, that works with compiler-versions currently found in the wild -- tested with gcc-4.4.7 (stock compiler on RedHat6), gcc-8.3.1, and clang-10 is:

    template<class...>  // or just <class> if genericity is not needed
    struct std_void {
        typedef void type;
    };
    
    template<template<typename...> class Map, typename K, typename V,
             typename = std_void<typename Map<K, V>::mapped_type>>
    void insert(Map<K, V>& store, const string &key, const string &value) {
        // ...
    }
    

    对于来自(辉煌的)未来的读者,无论如何,请使用@Evg(本文基于其提议)或@Igor-Tandetnik 提出的技术——if 您的编译器支持必要的功能.

    To a reader from the (glorious) future, by all means, use the techniques proposed by @Evg (on whose proposal this one is based) or the one by @Igor-Tandetnik -- if your compiler supports the necessary features.

    Evg 的答案——以及从它派生的这个答案——根据其类型是否定义了 mapped_type 来选择模板.Igor 的区别在于模板的 insert 方法采用的参数.两者都适合我的目的,但 Evg 更容易适应旧的编译器.

    Evg's answer -- and this one derived from it -- select the template based on whether or not its type defines a mapped_type. Igor's differentiates on the arguments taken by the template's insert-method. Either would've been suitable to my purposes, but Evg's was easier to adapt to the older compiler.

    最后,我必须发泄我对 C++ 状态的不满:这不应该那么困难.我让它工作了,但是一个试图阅读我的代码的同事不会理解它——不是没有多次通过它和无数的诅咒和陷阱!"

    In closing, I must vent my frustration with the state of C++: this shouldn't be so difficult. I got it to work, but a colleague trying to read my code will not understand it -- not without multiple passes through it and numerous curses and "gotchas!"

    是的,C++ 程序被编译(编译成二进制代码,而不是字节"代码),并且完整反射"所需的运行时类型信息 (RTTI) 被编译.是(非常)昂贵的.

    Yes, the C++ programs are compiled (into binary, rather than "byte", code), and the run-time type information (RTTI) necessary for the full "reflection" is (very) expensive.

    但是我需要的不需要运行时反射!所有必要的信息在编译时都是已知的,那么为什么在首次引入三十年后我还没有所有必要的语言特性呢?即使 10 年等待这样的功能也太长了——芯片制造商在同一时期让处理器变胖了 32 倍.

    But what I needed does not require run time reflection! All of the information necessary is known at compile time, so why don't I have all the necessary language-features already, three decades after it was first introduced? Even 10 years is way too long a wait for such functionality -- chip-manufacturers make processors 32-times fatter during the same period.

    constexpr 是这样的,谢谢你,但它是最近添加的,我的编译器仍然不支持它......

    The constexpr is sort of it, thank you kindly, but it was added so recently, my compiler still has no support for it...

    这篇关于区分地图和集合的模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆