Adapting non-iterable containers to be iterated via custom templatized iterator

Posted by DAldridge on Stack Overflow See other posts from Stack Overflow or by DAldridge
Published on 2012-06-22T23:18:30Z Indexed on 2012/06/23 3:16 UTC
Read the original article Hit count: 179

Filed under:
|

I have some classes, which for various reasons out of scope of this discussion, I cannot modify (irrelevant implementation details omitted):

class Foo { /* ... irrelevant public interface ... */ };

class Bar {
  public:
    Foo& get_foo(size_t index) { /* whatever */ }
    size_t size_foo() { /* whatever */ }
};

(There are many similar 'Foo' and 'Bar' classes I'm dealing with, and it's all generated code from elsewhere and stuff I don't want to subclass, etc.)

[Edit: clarification - although there are many similar 'Foo' and 'Bar' classes, it is guaranteed that each "outer" class will have the getter and size methods. Only the getter method name and return type will differ for each "outer", based on whatever it's "inner" contained type is.

So, if I have Baz which contains Quux instances, there will be Quux& Baz::get_quux(size_t index), and size_t Baz::size_quux().]

Given the design of the Bar class, you cannot easily use it in STL algorithms (e.g. for_each, find_if, etc.), and must do imperative loops rather than taking a functional approach (reasons why I prefer the latter is also out of scope for this discussion):

Bar b;
size_t numFoo = b.size_foo();
for (int fooIdx = 0; fooIdx < numFoo; ++fooIdx) {
  Foo& f = b.get_foo(fooIdx);
  /* ... do stuff with 'f' ... */
}

So... I've never created a custom iterator, and after reading various questions/answers on S.O. about iterator_traits and the like, I came up with this (currently half-baked) "solution":

First, the custom iterator mechanism (NOTE: all uses of 'function' and 'bind' are from std::tr1 in MSVC9):

// Iterator mechanism...
template <typename TOuter, typename TInner>
class ContainerIterator : public std::iterator<std::input_iterator_tag, TInner> {
  public:
    typedef function<TInner& (size_t)> func_type;

    ContainerIterator(const ContainerIterator& other) : mFunc(other.mFunc), mIndex(other.mIndex) {}

    ContainerIterator& operator++() { ++mIndex; return *this; }

    bool operator==(const ContainerIterator& other) {
      return ((mFunc.target<TOuter>() == other.mFunc.target<TOuter>()) && (mIndex == other.mIndex));
    }

    bool operator!=(const ContainerIterator& other) { return !(*this == other); }

    TInner& operator*() { return mFunc(mIndex); }

  private:
    template<typename TOuter, typename TInner>
    friend class ContainerProxy;

    ContainerIterator(func_type func, size_t index = 0) : mFunc(func), mIndex(index) {}

    function<TInner& (size_t)> mFunc;
    size_t mIndex;
};

Next, the mechanism by which I get valid iterators representing begin and end of the inner container:

// Proxy(?) to the outer class instance, providing a way to get begin() and end()
// iterators to the inner contained instances...
template <typename TOuter, typename TInner>
class ContainerProxy {
  public:
    typedef function<TInner& (size_t)> access_func_type;
    typedef function<size_t ()> size_func_type;

    typedef ContainerIterator<TOuter, TInner> iter_type;

    ContainerProxy(access_func_type accessFunc, size_func_type sizeFunc) : mAccessFunc(accessFunc), mSizeFunc(sizeFunc) {}

    iter_type begin() const {
      size_t numItems = mSizeFunc();
      if (0 == numItems) return end();
      else return ContainerIterator<TOuter, TInner>(mAccessFunc, 0);
    }
    iter_type end() const {
      size_t numItems = mSizeFunc();
      return ContainerIterator<TOuter, TInner>(mAccessFunc, numItems);
    }

  private:
    access_func_type mAccessFunc;
    size_func_type mSizeFunc;
};

I can use these classes in the following manner:

// Sample function object for taking action on an LMX inner class instance yielded
// by iteration...
template <typename TInner>
class SomeTInnerFunctor {
  public:
    void operator()(const TInner& inner) {
      /* ... whatever ... */
    }
};

// Example of iterating over an outer class instance's inner container...
Bar b; /* assume populated which contained items ... */
ContainerProxy<Bar, Foo> bProxy(
  bind(&Bar::get_foo, b, _1),
  bind(&Bar::size_foo, b));
for_each(bProxy.begin(), bProxy.end(), SomeTInnerFunctor<Foo>());

Empirically, this solution functions correctly (minus any copy/paste or typos I may have introduced when editing the above for brevity).

So, finally, the actual question:

I don't like requiring the use of bind() and _1 placeholders, etcetera by the caller. All they really care about is: outer type, inner type, outer type's method to fetch inner instances, outer type's method to fetch count inner instances.

Is there any way to "hide" the bind in the body of the template classes somehow? I've been unable to find a way to separately supply template parameters for the types and inner methods separately...

Thanks!
David

© Stack Overflow or respective owner

Related posts about c++

Related posts about templates