I have a polymorphic interface
struct Interface {
Interface(SomeType& other)
: range([=](){ return other.my_range(); }), /*...*/ {}
Interface(SomeOtherType& other)
: range([=](){ return other.some_range(); }), /*...*/ {}
const std::function<Range(void)> range;
/// ...
};
The elements in both ranges are of the same type (e.g. int
), but the types returned by my_range()
and by some_range()
are different, e.g. one can be a filtered counting range
and the other a transformed filtered counting range
. For the interface I need a single Range
type.
I've tried using boost::any_range
but the performance is significantly worse. I would like to avoid having to copy the range elements into a vector
and returning the vector instead.
Are there any alternatives to any_range
and copying?
Kind of, but not really.
You want to access data sequentially when you don't know how it's stored. You have three options:
So the second is not possible due to the constraint that you want to use an interface. The first and the third both come with overhead.
The obvious way of doing the third thing is any_range
. But it's not the only way, depending on what you want to do. The problem with any_range
is that in a simple for-each loop, there are three virtual calls for every element: the increment, the comparison, and the dereference.
As long as all you want to do is simple for-each iteration, you could reduce the overhead to one virtual call by implementing the loop on the interface level:
struct Interface {
Interface(SomeType& other)
: traverse([=](std::function<void(int)> body) {
for (int i : other.my_range()) body(i);
}) {}
const std::function<void (std::function<void(int)>)> traverse;
};
Of course that only works as long as the ways you use the range are very limited.