Search code examples
c++boostboost-range

How to join multiple boost ranges and return as a result from function w/o using boost::any_range


Example:

SomeType bar::foo() const {
  SomeType retVal;
  for (auto i = 0u; i < 10; ++i) {
    retVal = boost::range::join(retVal, m_someDataContainer.equal_range(i));
  }
  return retVal;
}


Lets say, for simplicity, the m_someDataContainer and the bar class are defined as following:

typedef boost::multi_index_container<
    int, bmi::indexed_by<bmi::hashed_unique<bmi::tag<struct someTag>,
                                           bmi::identity<int>>>> Data;
class bar {
public:
  SomeType foo() const;

private:
  Data m_someDataContainer;
};

The questions are: How do I figure out the return type of foo() and how do I join these ranges without using boost::any_range

EDIT1: Looks like it is quite impossible, calling join in loop on previous joined value makes the result type a nested type of joined_range of joined_range of joined_range ... and so on, which, I guess cannot be deduced easily if at all


Solution

  • Since you have (or can generate) a range of ranges of the same type, you need a flattening range. Using Jesse Good's flatten from Iterating over a range of ranges:

    return flatten(boost::irange(0, 10)
        | boost::adaptors::transform(
            [this](int i){ return m_someDataContainer.equal_range(i); }));
    

    Unfortunately I think that this will probably leave the iterators dangling, so you should adapt the flatten there to copy the range into its return value; you can do this with multiple inheritance:

    template<typename Cont> using FlatIteratorRange
        = boost::iterator_range<flattening_iterator<decltype(std::declval<Cont>().begin())>;
    
    template<typename Cont>
    struct FlatRange
        : private Cont
        , public FlatIteratorRange<Cont>
    {
        explicit FlatRange(Cont const& c)
            : Cont(c)
            , FlatIteratorRange<Cont>(
                flat_iter(this->Cont::begin(), this->Cont::end()),
                flat_iter(this->Cont::end()));
        {}
    }
    
    template<typename Cont>
    auto flatten(Cont const& c) -> FlatRange<Cont>
    {
        return FlatRange<Cont>(c);
    }