Создание пользовательского класса диапазона, который оборачивает адаптеры повышения - PullRequest
0 голосов
/ 18 октября 2018

У меня есть класс, который применяет некоторые адаптеры повышающего преобразования к диапазону (например, в действительности это намного сложнее, чем это):

struct Foo {
    auto range() const {
        return boost::irange(0, 10)
            | boost::adaptors::transformed([] (auto x) { return x * 2; });
    }

    auto begin() const { return range().begin(); }
    auto end() const { return range().end(); }
};

Одно это позволяет нам выполнять итерации поFoo с использованием диапазона для:

for (auto x : Foo()) {
    std::cout << num << std::endl;
}

Однако это не подходит для других адаптеров повышения мощности или операций с диапазоном (например, boost::join):

auto bad = boost::join(boost::irange(0, 10), Foo());
auto also_bad = Foo() | boost::adaptors::transformed([] (auto x) { return x + 1; });

ОбаВышеуказанное вызывает некоторые неприятные ошибки шаблона.Первый (bad):

In file included from test.cpp:4:
/usr/local/include/boost/range/join.hpp:30:70: error: no type named 'type' in
      'boost::range_iterator<const Foo, void>'
            BOOST_DEDUCED_TYPENAME range_iterator<SinglePassRange1>::type,
            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~
/usr/local/include/boost/range/join.hpp:44:28: note: in instantiation of template class
      'boost::range_detail::joined_type<const Foo, const boost::integer_range<int> >' requested
      here
    : public range_detail::joined_type<SinglePassRange1, SinglePassRange2>::type
                           ^
test.cpp:34:16: note: in instantiation of template class 'boost::range::joined_range<const Foo,
      const boost::integer_range<int> >' requested here
    auto bad = boost::join(Foo(), range);
               ^

...

И последний (also_bad):

In file included from test.cpp:1:
In file included from /usr/local/include/boost/range/any_range.hpp:17:
In file included from /usr/local/include/boost/range/detail/any_iterator.hpp:22:
In file included from /usr/local/include/boost/range/detail/any_iterator_wrapper.hpp:16:
In file included from /usr/local/include/boost/range/concepts.hpp:24:
/usr/local/include/boost/range/value_type.hpp:26:70: error: no type named 'type' in
      'boost::range_iterator<Foo, void>'
    struct range_value : iterator_value< typename range_iterator<T>::type >
                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~
/usr/local/include/boost/range/adaptor/replaced.hpp:109:40: note: in instantiation of template
      class 'boost::range_value<Foo>' requested here
                BOOST_DEDUCED_TYPENAME range_value<SinglePassRange>::type>& f )
                                       ^
test.cpp:35:27: note: while substituting deduced template arguments into function template
      'operator|' [with SinglePassRange = Foo]
    auto also_bad = Foo() | boost::adaptors::transformed([] (auto x) { return x * 2; });
                          ^
...

Кажется, обе ошибки жалуются на то, что Foo недиапазон.Я попытался добавить operator OutContainer() и typedefs для iterator / const_iterator, как предлагалось здесь , но безрезультатно.Что я должен сделать с Foo, чтобы он хорошо играл с этими операциями диапазона?

1 Ответ

0 голосов
/ 18 октября 2018

Ошибка очень полезна в этом случае.Ваш тип должен моделировать SinglePassRange, и это не так.Есть страница о том, как это сделать, и хотя вы предоставили begin() и end(), вы не указали псевдонимы типов для iterator и const_iterator.Следовательно, вы не моделируете SinglePassRange.

Но на самом деле очень хорошо, что ваш код не прошел, потому что он также плох.У вас есть begin() звонок range().begin() и end() звонок range().end().Это итераторы в различных диапазонах .Так что в любом случае это неопределенное поведение - вы не соответствуете семантическим понятиям SinglePassRange.

. Более простое решение - просто использовать Foo() напрямую.Это уже работает:

auto good = boost::join(boost::irange(0, 10), Foo().range());
auto also_good = Foo().range() | boost::adaptors::transformed([] (auto x) { return x + 1; });

А значит, вам просто нужно написать одну функцию: range()

...