Каковы преимущества использования boost :: any_range?

Каковы преимущества использования boost::any_range?
Вот пример:

typedef boost::any_range<
int
, boost::forward_traversal_tag
, int
, std::ptrdiff_t
> integer_range;

void display_integers(const integer_range& rng)
{
boost::copy(rng,
std::ostream_iterator<int>(std::cout, ","));

std::cout << std::endl;
}

int main(){
std::vector<int> input{ ... };
std::list<int> input2{ ... };
display_integers(input);
display_integers(input2);
}

Но та же функциональность с большей эффективностью может быть достигнута с помощью параметра шаблона, который удовлетворяет концепции ForwardRange:

template <class ForwardRange>
void display_integers(const ForwardRange& rng)
{
boost::copy(rng,
std::ostream_iterator<int>(std::cout, ","));

std::cout << std::endl;
}

Поэтому я ищу сценарии, когда стоит использовать any_range. Может быть, я что-то упустил.

10

Решение

Эта техника называется Type Erasure. Есть полная статья с описанием плюсов и минусов на примере any_iterator: О напряженности между объектно-ориентированным и общим программированием в C ++.

Можно скрыть (в отдельном файле / библиотеке) реализацию / определение

void display_integers(const integer_range& rng)

Но в случае

template <class ForwardRange>
void display_integers(const ForwardRange& rng)

Вы должны предоставить исходный код пользователям (или, по крайней мере, сделать явные экземпляры где-то).

Более того, в первом случае display_integers будет скомпилирован только один раз, но во втором он будет скомпилирован для каждого типа пройденного диапазона.

Кроме того, вы можете иметь где-то

integer_range rng;

и в течение жизни rng Вы можете назначить диапазоны разные типы к нему:

vector<int> v;
list<int> l;
integer_range rng;
rng = v;
rng = l;

Самым большим недостатком стирания типа является его стоимость во время выполнения; все операции являются виртуальными и не могут быть встроены (легко).


Постскриптум Другой известный пример стирания типа станд :: функция

17

Другие решения

boost::any_range может использоваться для возврата диапазонов из функций. Представьте себе следующий пример:

auto make_range(std::vector<int> v) -> decltype(???)
{
return v | filter([](int x){ return x % 2 == 0;})
| transform([](int x){ return x * 2;});
}

*: gcc не компилирует вышеперечисленное, не оборачивая его std::function, косилка лязг 3.2 работает путем прямого прохождения лямбда

Очень трудно узнать, что возвращается из этой функции. Также, лямбда и decltype не работают вместе, поэтому мы не можем вывести тип, используя decltype при прохождении только лямбда. Одним из решений является использование boost::any_range как в вашем примере (другой обходной путь должен использовать std::function как указано Евгений Панасюк в комментариях):

integer_range make_range(std::vector<int> v)
{
return v | filter([](int x){ return x % 2 == 0;})
| transform([](int x){ return x * 2;});
}

Рабочий пример с gcc с помощью std::function,

Рабочий пример с лязгом прохождение лямбды напрямую.

10