简体   繁体   English

如何遍历Boost Multi_index容器的索引?

[英]How to iterate through the indices of a Boost Multi_index container?

I have a boost::multi_index::multi_index_container container having six different ordered_non_unique indices. 我有一个boost::multi_index::multi_index_container容器,它具有六个不同的ordered_non_unique索引。 The idea is to be able to sort the data along these six indices (as a means of ranking solutions using multiple criteria). 想法是能够沿着这六个索引对数据进行排序(作为使用多个标准对解决方案进行排名的一种手段)。

The issue I'm facing is while retrieving the indices in a loop. 我面临的问题是在循环检索索引时。 Boost requires me to use the following syntax to get (say) the 4th index: Boost要求我使用以下语法来获取(例如)第四个索引:

const result_multi::nth_index<1>::type &legs_index = result.get<4>();

What I'm trying to do is to put the above statement in a loop that runs between 0 to 5, so that I can use the same code on all six indices. 我正在尝试将上述语句放入0到5之间的循环中,以便可以在所有六个索引上使用相同的代码。 Of course, the following code fragment would not compile: 当然,以下代码片段将无法编译:

for (size_t i = 0; i < 5; ++i) {
  const result_multi::nth_index<1>::type &index = result.get<i>();
  ...
  ... Display result sorted along the i-th index
  ...
 }

As the get<i> is a template that needs to be defined during compilation. 由于get<i>是在编译期间需要定义的模板。

How can I use achieve the above functionality so that I don't need to duplicate the code 6 times? 如何使用以实现上述功能,而无需重复代码6次? It seems boost:preprocessor may help in doing so, but am unable to figure out exactly how to use it - any pointers would be really appreciated! 似乎boost:preprocessor可能会这样做,但是无法确切地知道如何使用它-任何指针将不胜感激!

EDIT : I would really appreciate a non-C++11 solution as well, to complement the excellent answer using one. 编辑 :我也非常感谢非C ++ 11解决方案,以补充使用一个出色的答案。 (For non-technical reasons, I'm forced to use a legacy version of gcc). (出于非技术原因,我被迫使用旧版gcc)。

If you can't use C++14, the backporting to C++03 with Boost could look like this: 如果您不能使用C ++ 14,则通过Boost向C ++ 03的反向移植可能如下所示:

Live Coliru Demo 现场Coliru演示

#include <boost/type_traits/integral_constant.hpp>

template<typename T,T N0,T N1,typename F>
void static_for(F f)
{
  static_for<T,N0,N1>(f,boost::integral_constant<bool,(N0<N1)>());
}

template<typename T,T N0,T N1,typename F>
void static_for(F f,boost::true_type)
{
  f(boost::integral_constant<T,N0>());
  static_for<T,N0+1,N1>(f);
}

template<typename T,T N0,T N1,typename F>
void static_for(F f,boost::false_type)
{
}

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/identity.hpp>

using namespace boost::multi_index;
typedef multi_index_container<
  int,
  indexed_by<
    ordered_non_unique<identity<int> >,
    ordered_non_unique<identity<int>,std::greater<int> >,
    ordered_non_unique<identity<int> >,
    ordered_non_unique<identity<int>,std::greater<int> >,
    ordered_non_unique<identity<int> >,
    ordered_non_unique<identity<int>,std::greater<int> >
  >
> result_multi;

#include <iostream>

struct body
{
  body(result_multi& result):result(result){}

  template<typename I>
  void operator()(I){
    typename result_multi::nth_index<I::value>::type& index=
      result.get<I::value>();

    std::cout<<"index #"<<I::value<<": ";
    for(typename result_multi::nth_index<I::value>::type::iterator
          b=index.begin(),
          e=index.end();
        b!=e;++b){
      std::cout<<*b<<" ";
    }
    std::cout<<"\n";
  }

  result_multi& result;
};

int main()
{
  result_multi result;
  for(int i=0;i<3;++i)result.insert(i);

  static_for<int,0,6>(body(result));
}

which is considerably uglier. 这非常难看。 Another alternative is to use the preprocessor with BOOST_PP_REPEAT . 另一种选择是将预处理器与BOOST_PP_REPEAT一起使用。 I'm not sure myself which solution looks best, though I think I'd favor the first as it's better prepared for C++14 upgrading: 我不确定自己哪种解决方案最合适,尽管我认为我会偏爱第一种,因为它为C ++ 14升级做好了更好的准备:

Live Coliru Demo 现场Coliru演示

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/identity.hpp>

using namespace boost::multi_index;
typedef multi_index_container<
  int,
  indexed_by<
    ordered_non_unique<identity<int> >,
    ordered_non_unique<identity<int>,std::greater<int> >,
    ordered_non_unique<identity<int> >,
    ordered_non_unique<identity<int>,std::greater<int> >,
    ordered_non_unique<identity<int> >,
    ordered_non_unique<identity<int>,std::greater<int> >
  >
> result_multi;

#include <boost/preprocessor/repetition/repeat.hpp>
#include <iostream>

int main()
{
  result_multi result;
  for(int i=0;i<3;++i)result.insert(i);

#define BODY(z,i,_)                                        \
{                                                          \
  result_multi::nth_index<i>::type& index=result.get<i>(); \
                                                           \
  std::cout<<"index #"<<i<<": ";                           \
  for(result_multi::nth_index<i>::type::iterator           \
        b=index.begin(),                                   \
        e=index.end();                                     \
      b!=e;++b){                                           \
    std::cout<<*b<<" ";                                    \
  }                                                        \
  std::cout<<"\n";                                         \
}

BOOST_PP_REPEAT(6,BODY,~)

#undef BODY
}

You need some metaprogramming to do this, namely replacing the run-time for with a compile-time construct that can iterate over types representing the constants 0,...,5. 你需要一些元编程来做到这一点,即更换运行时间for一个编译时间结构,它可以遍历表示常数0,...,5 种类型 A very simple static_for relying on C++14 capabilities is shown below. 下面显示了一个非常简单的static_for依赖C ++ 14功能。 Note that the generic lambda function substituting for the for body is passed a std::integral_constant i whose numerical value is obtained through operator() , hence the " i() " in " auto& index=result.get<i()>(); ". 注意,通用lambda函数代替所述for身体传递一个std::integral_constant i是通过获得其数值 operator()因而有“ i() ”中的“ auto& index=result.get<i()>(); “。

Live Coliru Demo 现场Coliru演示

#include <type_traits>

template<typename T,T N0,T N1,typename F>
void static_for(F f)
{
  static_for<T,N0,N1>(f,std::integral_constant<bool,(N0<N1)>{});
}

template<typename T,T N0,T N1,typename F>
void static_for(F f,std::true_type)
{
  f(std::integral_constant<T,N0>{});
  static_for<T,N0+1,N1>(f);
}

template<typename T,T N0,T N1,typename F>
void static_for(F f,std::false_type)
{
}

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/identity.hpp>

using namespace boost::multi_index;
using result_multi=multi_index_container<
  int,
  indexed_by<
    ordered_non_unique<identity<int>>,
    ordered_non_unique<identity<int>,std::greater<int>>,
    ordered_non_unique<identity<int>>,
    ordered_non_unique<identity<int>,std::greater<int>>,
    ordered_non_unique<identity<int>>,
    ordered_non_unique<identity<int>,std::greater<int>>
  >
>;

#include <iostream>

int main()
{
  result_multi result={0,1,2};

  static_for<int,0,6>([&](auto i){
    auto& index=result.get<i()>();

    std::cout<<"index #"<<i()<<": ";
    for(int x:index)std::cout<<x<<" ";
    std::cout<<"\n";
  });
}

Output: 输出:

index #0: 0 1 2 
index #1: 2 1 0 
index #2: 0 1 2 
index #3: 2 1 0 
index #4: 0 1 2 
index #5: 2 1 0

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM