【问题标题】:Boost::multi_index with mapBoost::multi_index 与地图
【发布时间】:2015-10-20 15:21:34
【问题描述】:

我有一个关于修改 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&lt;...&gt; 中的参数。

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 是返回 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 函子一起使用时将返回 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有没有更好的解决方案?

【问题讨论】:

    标签: c++ c++11 boost boost-multi-index


    【解决方案1】:

    Q1 修改任何字段(即使是那些 与索引无关),需要使用函子并做一些事情 下面?

    简短的回答是肯定的,使用modify 以确保安全。如果您绝对确定您修改的数据不属于 any 索引,那么您可以使用丑陋的演员表:

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

    但强烈建议不要这样做。使用 C++11(您似乎正在使用),您可以使用 lambdas 而不是繁琐的用户定义函子:

    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");
    });
    

    【讨论】:

    • 谢谢!你拯救了我的夜晚))这正是我所需要的。
    猜你喜欢
    • 2016-03-23
    • 2011-03-29
    • 2017-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多