索引检索作为 boost::multi_index::sequenced<> 偏移量的函数
Index retrieval as a function of the boost::multi_index::sequenced<> offset
我处于被迫使用 std::vector
容器作为我的底层数据结构的情况。我正在尝试利用 boost::multi_index::sequenced<>
来隐藏矢量偏移量,并提供一种用于更丰富的数据查询的机制。我真的不想不必要地将所有数据从一个容器复制到另一个容器。
在下面的示例代码片段中,我有一个 class BarInterface
来管理向 Bar::foos
容器插入和删除元素。最初我尝试将对向量元素的引用存储为 typedef boost::multi_index_container
的元素,但这些元素对插入不稳定。
我想要做的是拥有一个自定义密钥提取器,它是 _bar
容器和 boost::multi_index::sequenced<>
索引的一个函数。因此,例如要获取元素的名称,我会找到序列偏移量 x
,然后是 _bar.foos[x].name
。所以,我实际上只是使用 boost::multi_index
作为针对可变大小向量的更丰富查询的代理。
struct Foo {
std::string name;
};
struct Bar {
std::vector<Foo> foos;
};
class BarInterface {
public:
struct Dummy {};
BarInterface(Bar& bar) : _bar(bar) {
for (auto& foo : bar.foos) {
_idx.get<1>().insert(Dummy{});
}
}
// Index
struct Name {};
typedef boost::multi_index_container<
Dummy, // We're not actually storing anything here
boost::multi_index::indexed_by<
boost::multi_index::sequenced<>, // Kept inline with vector order!
boost::multi_index::ordered_unique<
boost::multi_index::tag<Name>,
// I need something here that takes the boost::multi_index::sequenced<>
// key to get the offset x, and then returns this->_bar.foos[x].name!
>
>
> MultiIndex;
// Insert
void insert(const Foo& foo) {
_bar.foos.push_back(foo);
_idx.get<1>().insert(Dummy{});
}
// Remove
template <typename T>
void remove(T it) {
_bar.foos.erase(_bar.foos.begin() + std::distance(_idx.begin(), _idx.project<0>(it)));
_idx.erase(_idx.project<0>(it));
}
protected:
Bar& _bar;
MultiIndex _idx;
};
我知道 boost::multi_index
支持各种密钥提取器——用于成员变量、成员函数、全局函数等。但是,我似乎找不到说明如何生成密钥的示例作为 boost::multi_index::sequenced<>
索引的函数。这可能吗,或者是否有更好的选择?
这 非常 脆弱,我不建议使用这样的代码进行生产,但既然你要求它:
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <iostream>
#include <string>
#include <vector>
struct Foo {
std::string name;
};
struct Bar {
std::vector<Foo> foos;
};
class BarInterface;
struct Dummy
{
Dummy(const Foo& x): p(&x){}
Dummy(const Dummy&): p(nullptr){}
const Foo* p;
};
struct NameExtractor
{
NameExtractor(BarInterface* p): p(p){}
using result_type=std::string;
const result_type& operator()(const Dummy& d)const;
BarInterface* p;
};
class BarInterface {
public:
BarInterface(Bar& bar) :
_idx(boost::make_tuple(
boost::tuple<>(),
boost::make_tuple(NameExtractor(this), std::less<std::string>())
)),
_bar(bar)
{
for (auto& foo : bar.foos) {
_idx.get<1>().insert(bar.foos.back());
}
}
// Index
struct Name {};
typedef boost::multi_index_container<
Dummy, // We're not actually storing anything here
boost::multi_index::indexed_by<
boost::multi_index::random_access<>, // Kept inline with vector order!
boost::multi_index::ordered_unique<
boost::multi_index::tag<Name>,
NameExtractor
>
>
> MultiIndex;
// Insert
void insert(const Foo& foo) {
_bar.foos.push_back(foo);
_idx.get<1>().insert(_bar.foos.back());
}
// Remove
template <typename T>
void remove(T it) {
_bar.foos.erase(_bar.foos.begin() + std::distance(_idx.begin(), _idx.project<0>(it)));
_idx.erase(_idx.project<0>(it));
}
void remove(const char* name) {
remove(_idx.get<1>().find(name));
}
void print()const
{
auto key=_idx.get<1>().key_extractor();
for(const auto& d: _idx.get<1>()){
std::cout<<key(d)<<" ";
}
std::cout<<"\n";
}
protected:
friend NameExtractor;
Bar& _bar;
MultiIndex _idx;
};
const NameExtractor::result_type& NameExtractor::operator()(const Dummy& d)const
{
if(d.p){
return d.p->name;
}
else{
std::size_t offset=p->_idx.iterator_to(d)-p->_idx.begin();
return p->_bar.foos[offset].name;
}
}
int main()
{
Bar bar;
BarInterface bi(bar);
bi.insert(Foo{"hello"});
bi.insert(Foo{"bye"});
bi.insert(Foo{"Boost"});
bi.print();
bi.remove("bye");
bi.print();
bi.insert(Foo{"MultiIndex"});
bi.print();
}
输出
Boost bye hello
Boost hello
Boost MultiIndex hello
我处于被迫使用 std::vector
容器作为我的底层数据结构的情况。我正在尝试利用 boost::multi_index::sequenced<>
来隐藏矢量偏移量,并提供一种用于更丰富的数据查询的机制。我真的不想不必要地将所有数据从一个容器复制到另一个容器。
在下面的示例代码片段中,我有一个 class BarInterface
来管理向 Bar::foos
容器插入和删除元素。最初我尝试将对向量元素的引用存储为 typedef boost::multi_index_container
的元素,但这些元素对插入不稳定。
我想要做的是拥有一个自定义密钥提取器,它是 _bar
容器和 boost::multi_index::sequenced<>
索引的一个函数。因此,例如要获取元素的名称,我会找到序列偏移量 x
,然后是 _bar.foos[x].name
。所以,我实际上只是使用 boost::multi_index
作为针对可变大小向量的更丰富查询的代理。
struct Foo {
std::string name;
};
struct Bar {
std::vector<Foo> foos;
};
class BarInterface {
public:
struct Dummy {};
BarInterface(Bar& bar) : _bar(bar) {
for (auto& foo : bar.foos) {
_idx.get<1>().insert(Dummy{});
}
}
// Index
struct Name {};
typedef boost::multi_index_container<
Dummy, // We're not actually storing anything here
boost::multi_index::indexed_by<
boost::multi_index::sequenced<>, // Kept inline with vector order!
boost::multi_index::ordered_unique<
boost::multi_index::tag<Name>,
// I need something here that takes the boost::multi_index::sequenced<>
// key to get the offset x, and then returns this->_bar.foos[x].name!
>
>
> MultiIndex;
// Insert
void insert(const Foo& foo) {
_bar.foos.push_back(foo);
_idx.get<1>().insert(Dummy{});
}
// Remove
template <typename T>
void remove(T it) {
_bar.foos.erase(_bar.foos.begin() + std::distance(_idx.begin(), _idx.project<0>(it)));
_idx.erase(_idx.project<0>(it));
}
protected:
Bar& _bar;
MultiIndex _idx;
};
我知道 boost::multi_index
支持各种密钥提取器——用于成员变量、成员函数、全局函数等。但是,我似乎找不到说明如何生成密钥的示例作为 boost::multi_index::sequenced<>
索引的函数。这可能吗,或者是否有更好的选择?
这 非常 脆弱,我不建议使用这样的代码进行生产,但既然你要求它:
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <iostream>
#include <string>
#include <vector>
struct Foo {
std::string name;
};
struct Bar {
std::vector<Foo> foos;
};
class BarInterface;
struct Dummy
{
Dummy(const Foo& x): p(&x){}
Dummy(const Dummy&): p(nullptr){}
const Foo* p;
};
struct NameExtractor
{
NameExtractor(BarInterface* p): p(p){}
using result_type=std::string;
const result_type& operator()(const Dummy& d)const;
BarInterface* p;
};
class BarInterface {
public:
BarInterface(Bar& bar) :
_idx(boost::make_tuple(
boost::tuple<>(),
boost::make_tuple(NameExtractor(this), std::less<std::string>())
)),
_bar(bar)
{
for (auto& foo : bar.foos) {
_idx.get<1>().insert(bar.foos.back());
}
}
// Index
struct Name {};
typedef boost::multi_index_container<
Dummy, // We're not actually storing anything here
boost::multi_index::indexed_by<
boost::multi_index::random_access<>, // Kept inline with vector order!
boost::multi_index::ordered_unique<
boost::multi_index::tag<Name>,
NameExtractor
>
>
> MultiIndex;
// Insert
void insert(const Foo& foo) {
_bar.foos.push_back(foo);
_idx.get<1>().insert(_bar.foos.back());
}
// Remove
template <typename T>
void remove(T it) {
_bar.foos.erase(_bar.foos.begin() + std::distance(_idx.begin(), _idx.project<0>(it)));
_idx.erase(_idx.project<0>(it));
}
void remove(const char* name) {
remove(_idx.get<1>().find(name));
}
void print()const
{
auto key=_idx.get<1>().key_extractor();
for(const auto& d: _idx.get<1>()){
std::cout<<key(d)<<" ";
}
std::cout<<"\n";
}
protected:
friend NameExtractor;
Bar& _bar;
MultiIndex _idx;
};
const NameExtractor::result_type& NameExtractor::operator()(const Dummy& d)const
{
if(d.p){
return d.p->name;
}
else{
std::size_t offset=p->_idx.iterator_to(d)-p->_idx.begin();
return p->_bar.foos[offset].name;
}
}
int main()
{
Bar bar;
BarInterface bi(bar);
bi.insert(Foo{"hello"});
bi.insert(Foo{"bye"});
bi.insert(Foo{"Boost"});
bi.print();
bi.remove("bye");
bi.print();
bi.insert(Foo{"MultiIndex"});
bi.print();
}
输出
Boost bye hello
Boost hello
Boost MultiIndex hello