2015-10-20 60 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