Как скрыть сложный тип диапазона от диапазона-v3? - PullRequest
0 голосов
/ 07 декабря 2018

Мне нужен класс с методом, который возвращает некоторый диапазон, используя библиотеку range-v3.Чтобы реализовать такой класс, я могу написать все правильно в определении этого класса.Например:

#include <iostream>
#include <set>
#include <range/v3/view/transform.hpp>

class Alpha {
public:
  int x;
};

class Beta : public Alpha {};

class Foo {
public:
  std::set<Alpha*> s;

  auto r() { return s | ranges::v3::view::transform([](Alpha* a) { return static_cast<Beta*>(a); }) }
};

Однако в моем реальном случае функция Foo::r довольно сложна, и я хотел бы скрыть ее реализацию.В частности, реализация использует некоторые дополнительные библиотеки, которые в противном случае не нужно включать при объявлении класса Foo.

Однако, когда определение Foo::r отделено от его объявления, еговозвращаемый тип должен быть указан явно.decltype поставляется с некоторой помощью :

Заголовочные файлы:

class Foo {
public:
  std::set<Alpha*> s;

  using RangeReturn = decltype(std::declval<std::set<Alpha*>&>() | ranges::v3::view::transform(std::function<Beta*(Alpha*)>()));
  RangeReturn r();
};

Реализация, файл cpp:

#include "Foo.h"

Foo::RangeReturn Foo::r() {
    return s | ranges::v3::view::transform(std::function<Beta*(Alpha*)>{
      [](Alpha* a) { return static_cast<Beta*>(a); }
      });
}

Thisвыполняет непосредственную работу, скрывая фактическую реализацию Foo::r.Однако тип возвращаемого значения по-прежнему эффективно «пропускает» информацию о том, как строится диапазон.Что, вероятно, хуже, теперь я вынужден явно использовать объект std::function в конвейере диапазона.

Но действительно ли эта информация нужна пользователю возвращаемого диапазона?Все, что беспокоит пользователя Foo::r, это то, что он является итеративным.Он имеет:

  • begin(), дающий итератор к началу диапазона
  • end(), дающий некоторый итератор или страж
  • Итератор может быть увеличен доитерация по диапазону
  • Итератор может быть разыменован, давая некоторый тип T (Beta* в нашем примере).

Пользователю все равно, что есть преобразованиепосмотреть или нет, ни количество преобразований, фильтров и еще много чего.

Итак, мой вопрос - есть ли способ скрыть всю эту информацию?Я хотел бы иметь возможность написать что-то вроде этого:

В шапке:

class Foo {
public:
  std::set<Alpha*> s;

  Iterable<Beta*> r();
};

В файле cpp:

#include "Foo.h"

Iterable<Beta*> Foo::r() {
    return s | ranges::v3::view::transform([](Alpha* a) { return static_cast<Beta*>(a); });
}

Я могу принять фактчто созданный тип Iterable может содержать реальные вызовы функций, которые нельзя встроить из-за процесса сокрытия.Оптимизация во время соединения может или не сможет оптимизировать ее позже.

К сожалению, насколько мне известно, такой Iterable является просто концепцией, а не отдельным типом в библиотеке.

1 Ответ

0 голосов
/ 07 декабря 2018

Тип возвращаемого значения r(), который вы ищете: ranges::v3::any_view<Beta*>.

Обратите внимание, что применяется стирание типа, которое подразумевает некоторое снижение производительности во время выполнения, которое может быть значительным.Соответствующее обсуждение: низкая производительность стертых представлений .

Демонстрационная версия: https://wandbox.org/permlink/JylKIHD0NaQsRXdB

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