指向嵌套结构中成员变量的指针

时间:2014-12-18 02:44:06

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

对于下面的类,我如何表示指向qux的一个实例的成员变量Bar的指针?

struct Foo {
  struct Bar {
    int qux;
  } bar1, bar2;
};

当我使用boost::multi_index容器并且需要使用qux作为密钥时需要这个,这在密钥提取器中是必需的

template<class Class,typename Type,Type Class::*PtrToMember>
struct boost::multi_index::member

3 个答案:

答案 0 :(得分:3)

我假设打算创建一个Foo s的boost multi_index容器,并使用qux作为密钥。虽然qux不是Foo的成员,但您可以通过对成员Foo::bar1建立索引并为有序索引提供自定义比较谓词来实现此目的。例如,如果您尝试创建ordered_unique密钥,则可以这样写:

ordered_unique<member<Foo, Foo::Bar, &Foo::bar1>, compare_foo_bar>

其中compare_foo_barFoo::Bar的朋友,并被定义为需要:

struct compare_foo_bar
{
bool operator()(const Foo::Bar& lhs, const Foo::Bar& rhs)
{
  return lhs.qux < rhs.qux;
}
};

答案 1 :(得分:2)

在您的情况下,您有Class = Foo::BarType = intPtrToMember = &Foo::Bar::qux,因此这应该有效

boost::multi_index::member<Foo::Bar, int, &Foo::Bar::qux>

根据您在下面的评论,我修改了Boost.MultiIndex教程中的basic example以匹配您的用例。原始示例包含以下struct

/* an employee record holds its ID, name and age */
struct employee
{
  int         id;
  std::string name;
  int         age;

  employee(int id_,std::string name_,int age_):id(id_),name(name_),age(age_){}
  // ...
};

multi_index容器定义为

typedef multi_index_container<
  employee,
  indexed_by<
    ordered_unique<
      tag<id>,  BOOST_MULTI_INDEX_MEMBER(employee,int,id)>,
    ordered_non_unique<
      tag<name>,BOOST_MULTI_INDEX_MEMBER(employee,std::string,name)>,
    ordered_non_unique<
      tag<age>, BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >
> employee_set;

现在,让我们修改employee,以便employee::name实际上是嵌套struct Bar的成员,并说employee包含两个Bar实例。

struct employee
{
  int           id;
  struct Bar
  {
    Bar(std::string name) : name(name) {}

    std::string name;
  } bar1, bar2;
  int           age;

  // ...
};

但你不能修改这个声明

ordered_non_unique<
      tag<name>,BOOST_MULTI_INDEX_MEMBER(employee,std::string,name)>

直接指示嵌套的struct数据成员。相反,您需要将声明修改为

ordered_non_unique<
  tag<name>,BOOST_MULTI_INDEX_MEMBER(employee,employee::Bar,bar1)>

我们需要一种方法来对employee::Bar个对象进行排序,因此在其定义中添加一个比较运算符

struct Bar
{
  // ...
  bool operator<(Bar const& other) const { return name < other.name; }
};

通过这些更改,如果您使用标记name为容器编入索引,则会根据bar1.name数据成员对其进行排序。

这是complete working example

我还初始化bar2.name以包含bar1.name中包含的反向字符序列,并使用标记name2添加了基于索引的选项。

答案 2 :(得分:1)

您可以诉诸user-defined key extractors

struct Foobar1qux
{
  typedef int result_type;

  int operator()(const Foo &x)const{return x.bar1.qux;}
};

struct Foobar2qux
{
  typedef int result_type;

  int operator()(const Foo &x)const{return x.bar2.qux;}
};

typedef multi_index_container<
  Foo,
  indexed_by<
    ordered_non_unique<Foobar1qux>,
    ordered_non_unique<Foobar2qux>
  >
> multi_t1;

更通用的方法是级联密钥提取器,如Boost.MultiIndex文档的one of the examples所示:

template<class KeyExtractor1,class KeyExtractor2>
struct key_from_key
{
public:
  typedef typename KeyExtractor1::result_type result_type;

  key_from_key(
    const KeyExtractor1& key1_=KeyExtractor1(),
    const KeyExtractor2& key2_=KeyExtractor2()):
    key1(key1_),key2(key2_)
  {}

  template<typename Arg>
  result_type operator()(Arg& arg)const
  {
    return key1(key2(arg));
  }

private:
  KeyExtractor1 key1;
  KeyExtractor2 key2;
};

typedef multi_index_container<
  Foo,
  indexed_by<
    ordered_non_unique<
      key_from_key<
        member<Foo::Bar,int,&Foo::Bar::qux>,
        member<Foo,Foo::Bar,&Foo::bar1>
      >
    >,
    ordered_non_unique<
      key_from_key<
        member<Foo::Bar,int,&Foo::Bar::qux>,
        member<Foo,Foo::Bar,&Foo::bar2>
      >
    >
  >
> multi_t2;