iterator_range в заголовочном файле - PullRequest
2 голосов
/ 11 февраля 2010

Я хочу указать в заголовочном файле, что входные данные для функции будут iterator_range, и итератор может быть разыменован для получения int. Каков наилучший способ сделать это? Я не хочу говорить iterator_range<std::vector<int>::iterator>, поскольку это связывает реализацию для использования std::vector<int>.

Буду признателен за любые идеи, чтобы определить функцию наилучшим образом.

Ответы [ 2 ]

3 голосов
/ 11 февраля 2010

Обычный способ сделать это состоит в том, чтобы сделать диапазон параметром шаблона, а затем использовать его для проверки концепции:

template<class SinglePassRange>
void func(SinglePassRange const & nums)
{
   typedef typename boost::range_iterator<SinglePassRange>::type It;
   for(It it = nums.begin(), e = nums.end(); it != e; ++it)
   {
       int i = *it; 
       // Do something with your int
   } 
}

Это не скомпилируется, если ваш диапазон не содержит целые числа (или что-то конвертируемое в int), поэтому нет необходимости добавлять какие-либо дополнительные ограничения в интерфейс. Но если вы действительно хотите, вы можете добавить проверку концепции в начале своей функции (это обеспечит более качественные сообщения об ошибках вашим клиентам):

BOOST_CONCEPT_ASSERT(
    (boost::Convertible<typename boost::range_value<SinglePassRange>::type,
                        int>));

Наконец, если вы не хотите делать свою функцию шаблоном, я думаю, что вам придется справиться с взятием boost::iterator_range<std::vector<int>::iterator>, но в этом случае я не вижу никаких преимуществ в отношении взятия простого std::vector& .

2 голосов
/ 12 февраля 2010

Ваш вопрос кажется немного неясным и / или требования противоречивы.

Кажется, вы хотите, чтобы функция взяла boost::iterator_range<Container<int>::iterator>, где контейнером может быть что угодно, но вам не нужен шаблон функции.

Я не вижу, как этого можно добиться, за исключением перегрузки функции для всех итераторов, которые вы хотите поддерживать (становится еще хуже, если вы не имеете в виду контейнер int ).


Вот кое-что для развлечения, быстрый any_iterator, который использует стирание типов, так что он действительно может обернуть любой итератор (который ссылается на конкретный тип). (На самом деле с помощью Google вы можете найти более полный класс с тем же именем.)

Используется не шаблонной функцией суммы:

#include <numeric>
#include <vector>
#include <list>
#include <iostream>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/range/iterator_range.hpp>

namespace detail
{
template <class T>
class any_iterator_base
{
public:
    virtual ~any_iterator_base() {}
    virtual void increment() = 0;
    virtual bool equal(const any_iterator_base& other) const = 0;
    virtual T& dereference() const = 0;
};

template <class T, class Iter>
class any_iterator_impl: public any_iterator_base<T>
{
    Iter it;
public:
    any_iterator_impl(Iter it): it(it) {}
    virtual void increment() { ++it; }
    virtual bool equal(const any_iterator_base& other) const
    {
        //warning: throws if dynamic type of other is not the same as *this (can't compare iterators of different type)
        return it == dynamic_cast<const any_iterator_impl<T, Iter>&>(other).it;
    }
    virtual T& dereference() const { return *it; }
};

} //namespace detail

template <class T>
class any_iterator: public boost::iterator_facade<any_iterator<T>, T, boost::forward_traversal_tag>
{
    boost::shared_ptr<detail::any_iterator_base<T> > iter;
public:
    template <class Iter>
    any_iterator(Iter it): iter(new detail::any_iterator_impl<T, Iter>(it)) {}
private:
    friend class boost::iterator_core_access;

    void increment() { iter->increment(); }

    bool equal(const any_iterator& other) const
    {
        return iter->equal(*other.iter);
    }

    T& dereference() const { return iter->dereference(); }
};

int sum(const boost::iterator_range<any_iterator<int> >& range)
{
    return std::accumulate(range.begin(), range.end(), 0);
}

int main()
{
    int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    std::vector<int> vec(arr, arr + 5);
    std::list<int> li(arr + 5, arr + 10);
    std::cout << sum(boost::make_iterator_range(any_iterator<int>(vec.begin()), any_iterator<int>(vec.end()))) << '\n';
    std::cout << sum(boost::make_iterator_range(any_iterator<int>(li.begin()), any_iterator<int>(li.end()))) << '\n';
    std::cout << sum(boost::make_iterator_range(any_iterator<int>(arr), any_iterator<int>(arr + 10))) << '\n';
}

(Я все еще сомневаюсь, является ли это практическим решением. Для этих вещей созданы шаблоны.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...