容器模板参数 std::map 或 std::vector

Container template parameter std::map or std::vector

在我的一个项目中,我使用了树实现,其中我使用了容器 C=std::map<K,V> 维护每个树节点的子节点列表。每个树节点都有一个唯一的名称键 K 通常是 std::string.

template<typename V, template<typename Key=std::string,typename Type=TreeNode<V>,typename ...> typename C>
class TreeNode {
    typedef C<std::string, Value> cont_type;    
    typedef V data_type;

    cont_type childs;
    data_type value;

    cont_type::iterator genericFind(const K& k) {
        // Something generic here!!! 
    }
}

除了 std::map 不遵守树中的插入顺序这一事实之外,此实现对我来说效果很好。对于某些应用程序,我需要保持插入顺序,但对于其他应用程序,快速检索信息的需求更为重要。

因此 C 需要是

类型之一
std::vector<std::pair<K, V>> // keeping insertion order

std::map<K,V> // fast information retrivial

不,我的 TreeNode class 的实现有问题,仍然显式使用 std::map 的接口。特别是,它使用的成员函数 finderaseinsert 需要用通用的东西替换,其中两种容器类型的实现非常具体。

例如,每当我插入 std::vector 实现时,childs.find(key) 需要替换为 find(childs.begin(), childs.end(), key)

也许还有另一种我不知道的解决方案。这可能是 boost::multi_index,但我对此不太确定。

解决我的问题最简单的方法是什么?

使用相同的界面为您想要的容器"choices"创建通用包装器:

template <typename TKey, typename TValue>
class my_map_wrapper
{
private:
    std::map<TKey, TValue> _map;

public:
    // Same interface as 'my_vector_wrapper'.
    template <typename TEKey, typename TEValue>
    void emplace(TEKey&& key, TEValue&& value)
    {
        _map.emplace(std::make_pair(std::forward<TEKey>(key),
                                    std::forward<TEValue>(value)));
    }

    // ...
};


template <typename TKey, typename TValue>
class my_vector_wrapper
{
private:
    std::vector<std::pair<TKey, TValue>> _vec;

public:
    // Same interface as 'my_map_wrapper'.
    template <typename TEKey, typename TEValue>
    void emplace(TEKey&& key, TEValue&& value)
    {
        _vec.emplace_back(std::forward<TEKey>(key),
                          std::forward<TEValue>(value));
    }

    // ...
};

在包装器本身上模板化树节点 class:

template <typename TWrapper>
class TreeNode
{
private:
    TWrapper _container;

public:
    // Use "uniform" container interface...
};

您现在可以定义方便的类型别名以在用户代码中的容器之间进行选择:

template <typename TKey, typename TValue>
using MapTreeNode = TreeNode<my_map_wrapper<TKey, TValue>>;

template <typename TKey, typename TValue>
using VectorTreeNode = TreeNode<my_vector_wrapper<TKey, TValue>>;

您可以创建专用的重载函数并使用它们

template <typename Key, typename V>
auto my_find(std::map<Key, V>& m, const Key& key)
{
    return m.find(key);
}

template <typename Key, typename V>
auto my_find(std::vector<std::pair<Key, V>>& v, const Key& key)
{
    return std::find_if(v.begin(), v.end(), [&](const auto& p) {
        return p.first == key;
    });
}