Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ functor to output iterator adapter

Given a functor appropriate for use with std::for_each and friends:

template <typename T> struct Foo {
    void operator()(T const& t) { ... }
};

std::for_each(v.begin(), v.end(), Foo<Bar>());

Is there some standard way to convert this into an output iterator appropriate for use with std::copy and friends? (or the opposite adaptation) Something like:

std::copy(v.begin(), v.end(), functor_output_iterator(Foo<Bar>()));

Which would call the functor each time a value is assigned to the iterator:

adapter(F f) : functor(f) { }
adapter& operator*()  { return *this; }
operator=(T const& t) { functor(t); }
operator++()          { }
...

Or, alternatively:

std::for_each(..., some_adapter(std::ostream_iterator(std::cout)));

Background:

I have a class that exposes a collection using an output iterator:

template <typename It> GetItems(It out) {
    MutexGuard guard(mutex);
    std::copy(items.begin(), items.end(), out);
}

This allows callers to get access to the items without forcing them to use a specific container type and without messing around with locking or other internal details.

e.g., to get only unique items:

std::set<whatever> set;
obj->GetItems(std::inserter(set, set.end()));

This beats the hell out of:

ObjLock lock = obj->GetLock();
for (int i = 0; i < obj->GetItemCount(); ++i) {
    Item* item = obj->GetItem(i);
    ...

Now I also want to be able to aggregate these items, rather than copying them. (See this question). Where I would normally do something like:

std::for_each(v.begin(), v.end(), Joiner<Foo>());

Now I could make two separate methods for the same data elements, one that calls std::copy and one that calls std::for_each but it would be nice to be able to define just one such method, using an iterator or a functor, and have callers be able to pass either functors or iterators to it, adapting them as necessary to the appropriate type.

What I'm doing now is defining the aggregator in such a way that it can be used as either an output iterator or a functor, but this leads to unwanted complexity.

like image 416
Tim Sylvester Avatar asked Feb 07 '10 23:02

Tim Sylvester


1 Answers

How about boost::function_output_iterator?

like image 64
villintehaspam Avatar answered Sep 29 '22 00:09

villintehaspam