2014-05-01 20 views
0

如果使用std::map<std::string,object>來保留按名稱排序的對象,則地圖的value_typestd::pair<string,object>)是一個便利的類,它保證有用的功能,例如,哪個容器要使用map或set或else?

typedef std::map<std::string,object> object_map; 
typedef typename object_map::value_type named_object; 
void function(named_object const&); 

// with the following possible use case 
void foo(std::string const&name, object_map const &omap) 
{ 
    auto obj=omap.find(name); 
    if(obj==omap.end()) throw std::runtime_error("name not found"); 
    function(*obj); 
} 

到目前爲止,這麼好。後來我延長我的對象

struct extended_object : object { /* more data */ }; 

,並保持按名稱排序,也擴展對象,通過std::map<std::string,extended>。 我可以定義。

typedef std::map<std::string,extended_object> extended_object_map; 
typedef typename extended_object_map::value_type named_extended_object; 

不幸的是,我不能

void foo(std::string const&name, extended_object_map const& emap) 
{ 
    auto eobj=emap.find(name); 
    if(eobj==emap.end()) throw std::runtime_error("name not found"); 
    function(*eobj);  // cannot convert *eobj to const named_object& 
} 

現在,我的問題是如何解決這個問題呢?我考慮使用reinterpret_cast<>

function(reinterpret_cast<const named_object&>(*eobj)); 

基本上假定的named_objectnamed_extended_object數據佈局是完全一樣的基類和派生的。這是安全/可推薦的嗎? 另外,我考慮使用(而不是std::mapstd::set與主要類型 named_object和重新定義

struct named_extended_object : named_object { /* more data */ }; 

這種方法的問題是,爲了std::set::find()一個對象,我必須提供不只是一個名字字符串,但整個對象或甚至擴展對象。根據cppreference,std::set::find()將解決這個問題在C++ 14(過載3 & 4),但我應該在同一時間做什麼?

+0

嘗試下載的副本C++規範,您可以在此網站中找到鏈接:http://isocpp.org/get-started然後閱讀reinterpret_cast。我認爲你的結論是,在這種情況下reinterpret_cast是沒有意義的。有問題的類型是std :: pair,其中每個對象都有不同類型的對象。 Reinterpret_cast不會幫助你。 – shawn1874

+0

我不確定你是否理解一套是什麼。一組是鍵值對,但鍵和值都是相同的類型,所以當然你必須將唯一的類型對象傳遞給find,因爲這是找到任何東西的唯一可能方式。一套不可能以任何方式幫助你考慮你想要達到的目標。 std :: pair中的類型通過繼承關聯的事實並不意味着您可以簡單地從一個對類型轉換爲另一個類型。該語言不支持。 – shawn1874

+0

@ shawn1874 _「所以當然你必須將唯一的類型對象傳遞給find,因爲它是找到任何東西的唯一可能的方式。」_不在C++中14。請參閱[N3657](http://www.open-std.org/JTC1/sc22/WG21/docs/papers/2013/n3657.htm)和較早的[N3465](http://www.open-std。 org/jtc1/sc22/wg21/docs/papers/2012/n3465.pdf)建議它是基於。 –

回答

1

你的函數改爲

​​

然後調用它像

auto obj = omap.find(name); 
function(obj->first, obj->second); 
// or 
auto eobj = emap.find(name); 
function(eobj->first, eobj->second); 
+0

這並不能解決問題,但僅僅是避免了這個問題。如果'named_object'是我的類的公共接口中暴露的有用對象,那麼這種解決方案是不實際的。 – Walter

+0

成員變量與'first'和'second'不同的對象如何有用? –

+0

不是本身,但是如果我聲明一個只增加功能但沒有數據的平凡派生類,以便我可以毫無問題地向/從它轉換。 – Walter

1

地圖的value_typestd::pair<string,object>)是一個方便的類權證有用的功能

注:那就是不是地圖的value_type。這是std::pair<const string,object>

reinterpret_cast結果當named_extended_object通過參考訪問未定義的行爲,它違反了哪一些編譯器稱之爲「嚴格走樣」的規則,並可能導致程序無法正常運作,如果編譯器使用基於類型的別名分析優化。不要使用那樣的reinterpret_cast。在Handwavy Liskov Substitution Principle條款中,extended_object IS-A object,所以可以用extended_object代替object,但pair<T, extended_object> IS-NOT-A pair<T, object>因此不能互換使用。

我喜歡d Drmmr的答案,但如果你不想這樣做,另一種選擇是一個模板:

template<typename Obj> 
    void function(const std::pair<const std::string, Obj>&) 
    { 
    // ... 
    } 

這將接受pair<const string, object>pair<const string, extended_object>參數。如果模板的主體只嘗試訪問object中存在的成員,那麼它對於兩種參數類型都是完美的。

如果你不想暴露該模板功能的用戶,然後聲明兩個重載:

void function(const named_object&); 
void function(const named_extended_object&); 

然後在實現文件:

namespace { 
    template<typename Obj> 
    void function_impl(const std::pair<const std::string, Obj>&) 
    { 
     // common implementation ... 
    } 
} 

void function(const named_object& no) { function_impl(no); } 
void function(const named_extended_object& neo) { function_impl(neo); } 
相關問題