2015-10-20 58 views
2

我有一個關於在boost :: multi_index容器中修改元素的問題。 我所擁有的是結構,它包含一些預定義的參數和一些參數,這些參數在運行時定義並存儲在地圖中。 下面是結構的簡化版本:Boost :: multi_index與地圖

class Sdata{ 

    QMap<ParamName, Param> params; // parameters defined at run-time 

public: 

    int num; 
    QString key; 
    // more pre-defined parameters 
    // methods to modify the map 
    // as an example - mock version of a function to add the parameter 
    // there are more functions operating on the QMAP<...>, which follow the same 
    // rule - return true if they operated successfully, false otherwise. 
    bool add_param(ParamName name, Param value){ 
     if (params.contains(name)) return false; 
     params.insert(name, value); 
     return true;  
    } 

}; 

現在,我要遍歷預先定義的參數 SDATA的 的不同組合。要做到這一點,我去的boost :: multi_index:

typedef multi_index_container<Sdata, 
indexed_by < 
// by insertion order 
    random_access<>, 
//by key 
    hashed_unique< 
     tag<sdata_tags::byKey>, 
     const_mem_fun<Sdata, SdataKey, &Sdata::get_key> 
    >, 
//by TS 
    ordered_non_unique< 
     tag<sdata_tags::byTS>, 
     const_mem_fun<Sdata, TS, &Sdata::get_ts> 
    >, 

    /// more keys and composite-keys 
>//end indexed by 
> SdataDB; 

而現在,我想訪問和修改QMap<...>裏面的參數。

Q1不要我把它正確的,要修改任何字段(甚至是那些無關 指數),一個需要使用函子,做一些如下面?

Sdatas_byKey const &l = sdatas.get<sdata_tags::byKey>(); 
auto it = l.find(key); 
l.modify(it, Functor(...)) 

Q2如何獲得使用仿函數的方法的結果?也就是說,我有一個仿函數:

struct SdataRemoveParam : public std::unary_function<Sdata, void>{ 
    ParamName name; 
    SdataRemoveParam(ParamName h): name(h){} 
    void operator()(Sdata &sdata){ 
     sdata.remove_param (name); // this returns false if there is no param 
    } 
}; 

如何知道是否remove_param本示例中返回truefalse

Sdatas_byKey const &l = sdatas.get<sdata_tags::byKey>(); 
auto it = l.find(key); 
l.modify(it, SdataRemoveParam("myname")); 

我到了什麼,到目前爲止是拋出一個異常,所以是的boost :: multi_index的modify 方法,用Rollback仿函數使用時將返回 false

struct SdataRemoveParam : public std::unary_function<Sdata, void>{ 
    ParamName name; 
    SdataRemoveParam(ParamName h): name(h){} 
    void operator()(Sdata &sdata){ 
     if (!sdata.remove_param (name)) throw std::exception("Remove failed"); 
    } 
}; 

// in some other place 

Sdatas_byKey const &l = sdatas.get<sdata_tags::byKey>(); 
auto it = l.find(key); 
bool res = l.modify(it, SdataRemoveParam("myname"), Rollback); 

但是,我不喜歡這個決定,因爲它增加了從容器中刪除 條目的風險。

Q3有沒有更好的解決方案?

回答

4

Q1我能得到它正確,要修改任何字段(即使是那些 無關的指數),一個需要使用函子,做一些如下 ?

簡短答案是肯定的,請使用modify以確保安全。如果您是絕對確保你修改的數據不屬於任何指數,那麼你可以用一個醜陋的投獲得通過:

const_cast<Sdata&>(*it).remove_param("myname"); 

但這是強烈反對。隨着C++ 11(你似乎可以用),你可以使用lambda表達式,而不是繁瑣的用戶定義的函數子:

Sdatas_byKey &l = sdatas.get<sdata_tags::byKey>(); // note, this can't be const 
auto it = l.find(key); 
l.modify(it, [](Sdata& s){ 
    s.remove_param("myname"); 
}); 

Q2如何獲得使用仿函數的方法的結果?

再次,lambda表達式,這是非常簡單的:

bool res; 
l.modify(it, [&](Sdata& s){ 
    res=s.remove_param("myname"); 
}); 

隨着仿函數,你可以這樣做,但它需要更多的樣板(基本上,有SdataRemoveParam存放指向res)。

以下是隻是爲了好玩:如果你使用C++ 14可以封裝整個成語非常簡潔像這樣(C++ 11將是稍硬):

template<typename Index,typename Iterator,typename F> 
auto modify_inner_result(Index& i,Iterator it,F f) 
{ 
    decltype(f(std::declval<typename Index::value_type&>())) res; 
    i.modify(it,[&](auto& x){res=f(x);}); 
    return res; 
} 
... 
bool res=modify_inner_result(l,it, [&](Sdata& s){ 
    return s.remove_param("myname"); 
}); 
+0

謝謝!你救了我的傍晚))這正是我需要的。 – pausag