Boost::multi_index 有地图
Boost::multi_index with map
我对修改 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;
}
};
现在,我想遍历预定义参数的不同组合
数据。为此,我选择了 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 return 是 true
还是 false
:
Sdatas_byKey const &l = sdatas.get<sdata_tags::byKey>();
auto it = l.find(key);
l.modify(it, SdataRemoveParam("myname"));
到目前为止我所做的是抛出一个异常,这样 modify
boost::multi_index 的方法,当与 Rollback
函子一起使用时将 return
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有没有更好的解决方案?
Q1 Do I get it correctly that to modify any field (even those
unrelated to the index), one needs to use functors and do something as
below?
简短的回答是肯定的,为了安全起见使用 modify
。如果你绝对确定你修改的数据不属于 any 索引,那么你可以通过一个丑陋的转换:
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 How to get the result of the method using the functor?
同样,对于 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");
});
我对修改 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;
}
};
现在,我想遍历预定义参数的不同组合 数据。为此,我选择了 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 return 是 true
还是 false
:
Sdatas_byKey const &l = sdatas.get<sdata_tags::byKey>();
auto it = l.find(key);
l.modify(it, SdataRemoveParam("myname"));
到目前为止我所做的是抛出一个异常,这样 modify
boost::multi_index 的方法,当与 Rollback
函子一起使用时将 return
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有没有更好的解决方案?
Q1 Do I get it correctly that to modify any field (even those unrelated to the index), one needs to use functors and do something as below?
简短的回答是肯定的,为了安全起见使用 modify
。如果你绝对确定你修改的数据不属于 any 索引,那么你可以通过一个丑陋的转换:
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 How to get the result of the method using the functor?
同样,对于 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");
});