开发者

Boost Multi_Index Question

Sorry I can't be more specific in the title.

Let's say I have a class Foo

class Foo {
public:
    Foo() { m_bitset.reset(); }

    void set_i(int i) {
        m_bitset.set(1);
        m_i = i;
    }

    void set_j(int j) {
        m_bitset.set(2);
        m_j = j;
    }
    bool i_set() { return m_bitset(1); }
    bool j_set() { return开发者_运维知识库 m_bitset(2); }
    void clear_i() { m_bitset.reset(1); }
    void clear_j() { m_bitset.reset(2); }
    int get_i() {
        assert(i_set());
        return m_i;
    }
    int get_j() {
        assert(j_set());
        return m_j;
    }

private:
    int m_i, m_j;
    bitset<2> m_bitset;
};

And now I want to put Foo's into a multi_index.

typedef multi_index_container <
    Foo, 
    indexed_by<
        ordered_non_unique<BOOST_MULTI_INDEX_CONST_MEM_FUN( Foo, int, get_i)
        >,
        ordered_non_unique<BOOST_MULTI_INDEX_CONST_MEM_FUN( Foo, int, get_j)
        >
    >
> Foo_set;

What I'm trying to figure out is a way to have my multi_index sort the Foo's that have valid values of i or j (or both in the case of a composite_key and pass over the rest. So I don't want the code below to blow up, I just want to only return foos that have valid values for i.

for (Foo_set::nth_index<1>::type::iterator it = foos.get<1>().begin(); it != foos.get<1>().end(); ++it)
    cout << *it;


From skimming over the boost multi_index library docs I'd say what you want is not possible with this library. Looking at its rationale it appears that it is only made for indexing elements that are fully indexable over all "dimensions". (You might try asking on the boost users mailing list if there are any hacks to allow "sparse" index dimensions.)

Anyways - depending on the exact nature of your problem you might be able to work around it by using a boost::optional as indexing type. (Although I'm not even sure it's possible to index by boost::optional.)


Having assert() in your get_i() and get_j() functions will cause a hard program stop when multi_index asks for the i or j values for indexing.

It sounds like you want Null Object Pattern behaviour. I.e. m_i and m_j are data-types that take special values to indicate they are not set (if they were pointers, the NULL pointer would serve this purpose). Then your multi-index could index on those values, lumping all the null values together.

When accessing the data, you can use boost::range to filter out the null values:

// Predicate for null testing
struct is_not_null {
    bool operator()(const Foo& f) { return f.get_i() != NULL && f.get_j() != NULL; }
};

Foo_set::nth_index<1>::type& idx = foos.get<1>();
BOOST_FOREACH(const Foo& f, idx | filtered(is_not_null())) {
    ;// do something with the non-null Foo's
}

If you don't want to pollute the value-space of your variables (i.e. there is no meaningful null value that can be stored), you could also look into converting your m_i and m_j members into boost::optional's. With a bit more functor wrapping, you could create a composite index of <bool, int>, which would allow you to access set or unset Foo's separately. You can further compose the index to combine i and j with a composite index that looks like <bool, bool, int, int>.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜