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