2013-04-01 26 views
0

我有一个简单的bi_map的工作代码,这是一个双向映射类,用于在两个方向上存储关联的键值对。我目前的用法是,NID是某种数字编号或枚举,而OBJ是一个昂贵的不可复制的类对象。如何表示昂贵的与便宜的模板参数?

最近,我注意到我也需要bi_map<NID,std::string>std::string是一个便宜的OBJ应该真的只是复制。

什么是正确的方式来概括下面的代码,以便用户可以发信号是否有东西是昂贵的(我想使用指针/引用)或廉价(我想复制一切的价值),以便我可以使用正确的实施?

CODE

template<typename NID,typename OBJ> 
class bi_map 
{ 
    std::map<NID,OBJ*>  m_nid_2_ptr; 
    std::map<OBJ const*,NID> m_ptr_2_nid; 

public: 
    void insert(NID nid, OBJ& obj) 
    { 
    m_nid_2_ptr.insert(std::make_pair(nid, &obj)); 
    m_ptr_2_nid.insert(std::make_pair(&obj, nid)); 
    } 

    NID operator[](OBJ const& obj) const 
    { 
    return m_ptr_2_nid.at(&obj); 
    } 
    OBJ const& operator[](NID nid) const 
    { 
    return *(m_nid_2_ptr.at(nid)); 
    } 

    using pairs_cb = std::function<void(NID,OBJ const&)>; 
    void pairs(pairs_cb cb) const 
    { 
    for(const auto& p : m_nid_2_ptr) 
     cb(p.first, *p.second); 
    } 
    size_t size() const { return m_nid_2_ptr.size(); } 
}; 
+1

template ? –

+6

默认情况下进行复制。使用'bi_map <...,unique_ptr >'为昂贵的副本? (或其他一些跟踪指针的包装类型) – Pubby

+1

@Pubby +1我只是尝试了一个简单,薄的'my_namespace :: ref <>'可复制包装器,它工作得很棒。它不仅对我的'bi_map <>'有用,而且可以在任何时候需要在任何基于值的(STL)容器中存储引用时使用它。最重要的是,它是出色的分离问题:我可以保留所有基于容器的值,从而使代码更简单,更易于维护。谢谢! – kfmfe04

回答

5

一般情况下,可以有多种选择,我想,没有一个正确的答案。所以,让我们尝试找到适用于您的的东西。你说过你想区分廉价和昂贵的类型。最重要的设计选择是接口。你可以使用:

1)专业为指针模板,具有在您使用的是廉价的类型inteface的明确的线索

bi_map< int, std::string* > bi_map_1; // note * is to flag std::string as cheap 
bi_map< int, ExpensiveObject > bi_map_2; // no *, thus using heavy implementation 

这是这样实现的:

template< typename NID, typename OBJ > 
struct bi_map 
{ 
    // implementation for expensive objects, use OBJ* or std::shared_ptr<OBJ> 
}; 

// specialize of the second parameter is a pointer 
template< typename NID, typename OBJ > 
struct bi_map< NID, OBJ* > 
{ 
    // implementation for cheap objects, store a copy, i.e., use OBJ 
}; 

当然你也可以用&而不是*来标记这些类型,如果你发现更具可读性的话。

2)如果您要便宜/昂贵的分离在界面显示出来,也就是说,如果您想

bi_map< int, std::string > bi_map_1; // no * 
bi_map< int, ExpensiveObject > bi_map_2; // no * 

你需要的东西不同。一个解决办法是增加一个默认的模板参数:

template<typename> 
struct is_expensive_for_bi_map : std::false_type {}; 

template< typename IND, typename OBJ, bool = is_expensive_for_bi_map<OBJ>::value > 
struct bi_map 
{ 
    // implementation for expensive objects, use OBJ* or std::shared_ptr<OBJ> 
}; 

template< typename NID, typename OBJ > 
struct bi_map< NID, OBJ, false > 
{ 
    // implementation for cheap objects, store a copy, i.e., use OBJ 
}; 

,并为您考虑昂贵的每种类型,您可以添加

template<> 
struct is_expensive_for_bi_map<ExpensiveObject> : std::true_type {}; 

如果贵应该是默认的,只是扭转名称和适应其余,应该很容易。

0

另一种选择:

template<typename T> 
struct notExpensive { 
    static const bool value = FALSE; 
    typedef T REF; 
    static T& ref(T& x) { return x; } 
    static T& deref(T& x) { return x; } 
}; 
template<typename T> 
struct isExpensive { 
    static const bool value = TRUE; 
    typedef T* REF; 
    static T* ref(T& x) { return &x; } 
    static T deref(T* x) { return x; } 
}; 
template<typename T> 
struct expensiveP : public notExpensive<T> {}; 

// List of expensive types: 
template<> struct expensiveP<ExpensiveObject> : public isExpensive<T> {}; 

然后用expensiveP填写BIMAP调用。