1

Consider the following code:

#include <boost/range.hpp>
#include <boost/range/any_range.hpp>
#include <boost/range/join.hpp>

#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <list>

struct TestData {
  TestData() : m_strMem01("test"), m_intMem02(42), m_boolMem03(true) {}
  std::string m_strMem01;
  int m_intMem02;
  bool m_boolMem03;
};

struct IntComp {
  bool operator()(const TestData &s, int i) { return s.m_intMem02 < i; }
  bool operator()(int i, const TestData &s) { return i < s.m_intMem02; }
  bool operator()(const TestData &i, const TestData &s) {
    return i.m_intMem02 < s.m_intMem02;
  }
};
struct StrComp {
  bool operator()(const TestData &s, const std::string &str) {
    return s.m_strMem01 < str;
  }
  bool operator()(const std::string &str, const TestData &s) {
    return str < s.m_strMem01;
  }
  bool operator()(const TestData &i, const TestData &s) {
    return i.m_strMem01 < s.m_strMem01;
  }
};

typedef boost::any_range<TestData, boost::forward_traversal_tag,
                         const TestData &, std::ptrdiff_t> TestRange;

std::vector<TestData> vecData(10);
std::list<TestData> listData(20);

TestRange foo() {
  TestRange retVal;

  auto tmp1 = std::equal_range(vecData.cbegin(), vecData.cend(), 42, IntComp());
  retVal = boost::join(retVal, tmp1);
  auto tmp2 =
      std::equal_range(listData.cbegin(), listData.cend(), "test", StrComp());
  retVal = boost::join(retVal, tmp2);
  return retVal;
}

int main(int argc, char *argv[]) {
  auto res = foo();
  for (auto a : res) {
    std::cout << a.m_strMem01 << std::endl;
  }
  //std::cout << res[4].m_intMem02 << std::endl;
}

If you uncomment the last line the code fails since distance_to not implemented for any_forward_iterator_interface. I'm not sure what exactly I'm missing here, like implementing operator[] or distance_to but for what? My own version traversal tag? And why it doesn't work in the first place?

Coliru version

BartoszKP
  • 34,786
  • 15
  • 102
  • 130
kreuzerkrieg
  • 3,009
  • 3
  • 28
  • 59

2 Answers2

2

I would say the answer depends on your performance needs and your laziness when it comes to implementing a new iterator abstraction. The core reason for your [] operator not working is the fact that std::list<...> does not provide a random access traversal iterator. If you would have chosen a container that provides such an iterator. You any_range<...> could have taken the random_access_traversal_tag and everything would be fine. I think it's fair to say that it is not such a big deal to implement a random access iterator on top of a list by simply encapsulating the current index and count forward and backward within the list whenever a specific position is meant to be accessed, but it's clearly against the nature of the list performance-wise.

  • Is there a good reason to hold one of the collection in a list ?
  • Is there a good reason to access the resulting any_range by random ?
  • Is it worth the effort to provide a inefficient random access interface for std::list ?
Oncaphillis
  • 1,888
  • 13
  • 15
  • good point. First, list implementation explains why there is no operator[]. as per your questions. there is no list or vector in real life, it was just an example. in my case it is Boost MIC, which actually hides its implementation and I cannot implement operator[] on top of whatever. but now, when I understand 'WHY' I can look further in the MIC, maybe I can play around with the index, to provide random access. – kreuzerkrieg Nov 23 '14 at 13:16
  • @kreuzerkrieg Next time, just mention what you are **really** trying to achieve in the question then. Boost MIC makes it very clear when operator brackets are implemented (namely for `random_access` indices and `unique` indices). Of course, what you require here is the `random_access` index. If you use that, your any_range will have random access too. – sehe Nov 23 '14 at 13:18
  • yup, recently my oversimplified examples make more mess than saving from mess :( – kreuzerkrieg Nov 23 '14 at 13:21
1

Of course any_iterator (which underlies the any_range implementation) doesn't gratuitously emulate RandomAccess iterators for any odd iterator you pass.

If you want that, just make an iterator adaptor that does this (making it very slow to random access elements in a list - so don't do this).

sehe
  • 374,641
  • 47
  • 450
  • 633