2013-04-01 21 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調用。