使用可变模板的多地图 [英] Multikey map using variadic templates

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

问题描述

我试图使用c ++中的可变参数模板实现具有不同访问键的地图。我想得到的是使这样的语法工作:

  MultikeyMap< int,double,float> ; map1; // int和double是键,float是值类型
map1 [2] = 3.5;
map1 [5.7] = 22;

MultikeyMap< unsigned long long,int,float,double,int> map2; //更多键,int是值类型
map2 [100000000000ULL] = 56;

// etc ...

我现在看起来像:

 模板< class V,class ... Krest> 
class MultikeyMap;

template< class V,class K,class ... Krest>
class MultikeyMap< V,K,Krest ...> :protected std :: map< K,V>,
protected MultikeyMap< V,Krest ...>
{
public:
template< class T>
void insert(const T& t,const V& v)
{
std :: map< T,V&
}

template< class T>
const V * find(const T& k)
{
typedef std :: map< T,V& currentMap;
currentMap :: const_iterator it = currentMap :: find(k);
return it == currentMap :: end()? 0:& it-> second;
}

};

template< class V>
class MultikeyMap< V>
{};

我没有在插入中返回迭代器,并且发现使代码简单。



我发现此解决方案有两个主要缺陷。



首先参数列表。最初我试着写

  template< class K,class ... Krest,class V& 
class MultikeyMap< K,Krest ...,V>

但是编译器坚持 如果类模板部分特化的参数是

第二是从std ::的保护继承。

地图。我真的想使用组合而不是那样,但在这种情况下,我没有看到一种方式来访问存储的地图。如果有 static_if ,我会写

  template< class V,class K,class。 Krest> 
class MultikeyMap< V,K,Krest ...> :protected MultikeyMap< V,Krest ...>
{
public:
template< class T>
void insert(const T& t,const V& v)
{
static if(is_same< T,K> :: value)
m_map.insert(make_pair ,v));
else
MultikeyMap< V,Krest ...> :: insert(t,v);
}
private:
std :: map< K,V> m_map;
}

请咨询我提及的问题。如果有更好的方法,我会很高兴学习。



感谢您阅读。

解决方案

 模板< class V,class K,class ... Krest> 
class MultikeyMap:MultikeyMap< V,Krest ...>,
MultikeyMap< V,K&
{
使用ParentMM = MultikeyMap< V,Krest ...> ;;
using Parent = MultikeyMap< V,K> ;;
public:
using ParentMM :: insert;
using Parent :: insert;

使用ParentMM :: find;
using Parent :: find;

使用ParentMM :: operator [];
using Parent :: operator [];
}

template< class V,class K>
class MultikeyMap< V,K>
{
std :: map< K,V& k_map;
public:
void insert(const K& k,const V& v)
{
k_map.insert(std :: make_pair(k,v));
}

const V * find(const K& k)const
{
auto it = k_map.find(k);
if(it!= k_map.end())
return& it-> second;
return nullptr;
}

V& operator [](const K& k)
{
return k_map [k];
}
};

继承看起来很合适,因为它结合了多个实现的行为。我使基地是私有的,因为使用声明是要么使方法使成员可见。只有基本案例有 std :: map 作为成员。



我不会打扰模板参数,它是用于 std :: tuple 的同样的技巧,只是查找你最喜欢的STL实现。



EDIT



这里是相同的代码,我提到的微小的更改,所以键在类型参数中首先:

  template< class Head,class ... Tail> 
struct Helper:Helper< Tail ...> {
using Last = typename Helper< Tail ...> :: Last;
}

template< class T>
struct Helper< T> {
using Last = T;
}


template< class K,class ... Rest>
class MultikeyMap:MultikeyMap< Rest ...>,
MultikeyMap< K,typename Helper< Rest ...> :: Last>
{
使用ParentMM = MultikeyMap< Rest ...> ;;
using Parent = MultikeyMap< K,typename Helper< Rest ...> :: Last> ;;

public:
使用ParentMM :: insert;
using Parent :: insert;

使用ParentMM :: find;
using Parent :: find;

使用ParentMM :: operator [];
using Parent :: operator [];
}

template< class K,class V>
class MultikeyMap< K,V>
{
std :: map< K,V& k_map;
public:
void insert(const K& k,const V& v)
{
k_map.insert(std :: make_pair(k,v));
}

const V * find(const K& k)const
{
auto it = k_map.find(k);
if(it!= k_map.end())
return& it-> second;
return nullptr;
}

V& operator [](const K& k)
{
return k_map [k];
}
};


I'm trying to implement a map with different access keys using variadic templates in c++. What I want to get is to make such syntax work:

MultikeyMap<int, double, float> map1; // int and double are keys, float is value type 
map1[ 2 ] = 3.5;
map1[ 5.7 ] = 22;

MultikeyMap<unsigned long long, int, float, double, int> map2; // more keys, int is value type
map2[100000000000ULL] = 56;

// etc...

What I have now looks like:

template<class V, class... Krest>
class MultikeyMap;

template<class V, class K, class... Krest>
class MultikeyMap<V, K, Krest...> : protected std::map<K, V>,
                                    protected MultikeyMap<V, Krest...>
{
public:
    template<class T>
    void insert( const T& t, const V& v )
    {
        std::map<T, V>::insert( make_pair( t, v ));
    }

    template<class T>
    const V* find( const T& k )
    {
        typedef std::map<T,V> currentMap;
        currentMap::const_iterator it = currentMap::find( k );
        return it == currentMap::end() ? 0 : &it->second;
    }

};

template<class V>
class MultikeyMap<V>
{};

I didn't return iterators in insert and find to make the code simple.

I see two major defects in this solution.

First, the value type goes first in template arguments list. Initially I tried to write

template<class K, class... Krest, class V>
class MultikeyMap<K, Krest..., V>

but compiler insists that "if an argument for a class template partial specialization is a pack expansion it shall be the last argument".

Second is the protected inheritance from std::maps. I would really like to use composition instead of that, but in that case I don't see a way to access the stored maps. If there was a static_if, I would write

template<class V, class K, class... Krest>
class MultikeyMap<V, K, Krest...> : protected MultikeyMap<V, Krest...>
{
public:
    template<class T>
    void insert( const T& t, const V& v )
    {
        static if( is_same<T,K>::value )
            m_map.insert( make_pair( t, v ));
        else
            MultikeyMap<V, Krest...>::insert( t, v );
    }
private:
    std::map<K,V> m_map;
};

Please advice on the problems I mentioned. If there is a better approach, I'll be glad to learn.

Thanks for reading.

解决方案

Here's how I would do it:

template<class V, class K, class... Krest>
class MultikeyMap : MultikeyMap<V, Krest...>,
                    MultikeyMap<V, K>
{
    using ParentMM = MultikeyMap<V, Krest...>;
    using Parent = MultikeyMap<V, K>;
public:
    using ParentMM::insert;
    using Parent::insert;

    using ParentMM::find;
    using Parent::find;

    using ParentMM::operator[];
    using Parent::operator[];
};

template<class V, class K>
class MultikeyMap<V, K>
{
    std::map<K, V> k_map;
public:
    void insert(const K& k, const V& v)
    {
        k_map.insert(std::make_pair(k, v));
    }

    const V* find( const K& k ) const
    {
        auto it = k_map.find(k);
        if (it != k_map.end())
            return &it->second;
        return nullptr;
    }

    V& operator[](const K& k)
    {
        return k_map[k];
    }
};

Inheritance seems appropriate here, as it is combining the behaviour of multiple implementations. I made bases private because the using declaration is required either way to make the members visible. Only the base case has a std::map as a member.

I'm not going to bother reversing the template arguments, it's the same trick used for std::tuple, just look up your favourite STL implementation.

EDIT

Here's the same code, with the trivial change I mentioned, so keys come first in the type parameters:

template<class Head, class... Tail>
struct Helper : Helper<Tail...> {
    using Last = typename Helper<Tail...>::Last;
};

template<class T>
struct Helper<T> {
    using Last = T;
};


template<class K, class... Rest>
class MultikeyMap : MultikeyMap<Rest...>,
                    MultikeyMap<K, typename Helper<Rest...>::Last>
{
    using ParentMM = MultikeyMap<Rest...>;
    using Parent = MultikeyMap<K, typename Helper<Rest...>::Last>;

public:
    using ParentMM::insert;
    using Parent::insert;

    using ParentMM::find;
    using Parent::find;

    using ParentMM::operator[];
    using Parent::operator[];
};

template<class K, class V>
class MultikeyMap<K, V>
{
    std::map<K, V> k_map;
public:
    void insert(const K& k, const V& v)
    {
        k_map.insert(std::make_pair(k, v));
    }

    const V* find( const K& k ) const
    {
        auto it = k_map.find(k);
        if (it != k_map.end())
            return &it->second;
        return nullptr;
    }

    V& operator[](const K& k)
    {
        return k_map[k];
    }
};

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

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