2013-03-15 7 views
9

Каковы преимущества использования 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. Может быть, я чего-то не хватает.

ответ

15

Этот метод называется Типом Erasure. Существует полная статья, описывающая плюсы и минусы на примере any_iterator: On the Tension Between Object-Oriented and Generic Programming in C++.


можно скрыть реализацию/дефиниция из

void display_integers(const integer_range& rng) 

в отдельном файле/библиотеки.

Но в случае

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

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


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


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

integer_range rng; 

где-то. И при жизни ГСЧ - вы можете назначить пробегу different types to it:

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

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


P.S. другим известным примером стирания типа является std::function

+0

Помимо скрытия реализации, компилятор будет генерировать одно определение функции display_integers, а не генерировать версию для каждого используемого типа итератора. Это называется * code bloat *. –

+0

@ DavidRodríguez-dribeas, я уже сказал это: «в первом случае display_integers будут скомпилированы только один раз ...». Но обратите внимание: в случае стирания типа - разные классы «Реализация» будут генерироваться, когда вы передадите значения разных типов, это не «бесплатно». –

+0

Да, я просто хотел подчеркнуть, что прямая импликация уменьшает размытие кода шаблона * –

10

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;}); 
} 

*: НКУ не компилируется выше, не окружив его std::function, Хауэр лязг 3.2 работает непосредственно передавая лямбда

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

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

Рабочий пример with gcc использованием std::function.

Рабочий пример with clang Прохождение lambdas напрямую.

+2

Я думаю, что проблема может быть решена и другим способом: определение глобальной лямбда-переменной в подробном или скрытом пространстве имен, затем используйте параметр decltype для этой лямбда-переменной. Вот полный рабочий пример, раздвоенный с вашего сайта: http://liveworkspace.org/code/3hdxki$6 –

+1

@GaborMarton: Правильно, просто имейте в виду, что, возможно, [нет необходимости в бесплатной функции больше] (http: // liveworkspace.org/code/3hdxki$8). –

+0

В этом конкретном случае (в ответ) - проблем с лямбдой нет, потому что вы используете функцию std ::. decltype (v | boost :: adapters :: filters (std :: function {})). http://liveworkspace.org/code/czlAX$0 –