У меня полиморфный интерфейс
struct Interface {
Interface(SomeType& other)
: range([=](){ return other.my_range(); }), /*...*/ {}
Interface(SomeOtherType& other)
: range([=](){ return other.some_range(); }), /*...*/ {}
const std::function<Range(void)> range;
/// ...
};
Элементы в обоих диапазонах относятся к одному типу (например, int
), но типы возвращаются my_range()
и по some_range()
разные, например можно быть filtered counting range
а другой transformed filtered counting range
, Для интерфейса мне нужен один Range
тип.
Я пытался использовать boost::any_range
но производительность значительно хуже. Я хотел бы избежать копирования элементов диапазона в vector
и возвращая вектор вместо.
Есть ли альтернативы any_range
и копирование?
Вроде, но не совсем.
Вы хотите получать доступ к данным последовательно, когда не знаете, как они хранятся. У вас есть три варианта:
Поэтому второе невозможно из-за ограничений, которые вы хотите использовать интерфейс. Первый и третий оба идут с накладными расходами.
Очевидный способ сделать третье any_range
, Но это не единственный способ, в зависимости от того, что вы хотите сделать. Проблема с any_range
в том, что в простом цикле for-each есть три виртуальных вызова для каждого элемента: приращение, сравнение и разыменование.
Пока все, что вы хотите сделать — это просто для каждой итерации, вы можете сократить накладные расходы до одного виртуального вызова, реализовав цикл на уровне интерфейса:
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;
};
Конечно, это работает только до тех пор, пока способы использования диапазона очень ограничены.
Если известны только 2 известных типа (или фиксированное количество типов), то альтернативой может быть Boost.Variant. Вот пример использования:
#include <boost/variant.hpp>
#include <functional>
struct SomeType
{
typedef int range_t;
range_t my_range() const { return 1; }
};
struct SomeOtherType
{
typedef double range_t;
range_t some_range() const { return 3.14; }
};
typedef std::function<SomeType::range_t (void)> SomeTypeRange;
typedef std::function<SomeOtherType::range_t (void)> SomeOtherTypeRange;
typedef boost::variant<SomeTypeRange, SomeOtherTypeRange> Range;
struct Interface
{
Interface(const SomeType& other)
: range( SomeTypeRange([=](){ return other.my_range(); }) ) {}
Interface(const SomeOtherType& other)
: range( SomeOtherTypeRange([=](){ return other.some_range(); }) ) {}
Range range;
};
struct print_me_visitor : public boost::static_visitor<void>
{
public:
void operator()( const SomeTypeRange& i_st ) const
{
std::cout << "SomeTypeRange: " << i_st() << std::endl;
}
void operator()( const SomeOtherTypeRange& i_sot ) const
{
std::cout << "SomeOtherTypeRange: " << i_sot() << std::endl;
}
};
int main()
{
SomeType st;
SomeOtherType sot;
Interface i1( st );
Interface i2( sot );
boost::apply_visitor( print_me_visitor(), i1.range );
boost::apply_visitor( print_me_visitor(), i2.range );
return 0;
}