Написание C ++ 11 в стиле LINQ Select

Я пытаюсь написать методы в стиле LINQ для моего базового класса Iterator, от которого наследуются List и Sequence, но эти два контейнера будут иметь свои собственные реализации этих методов. Метод «Где» был довольно простым. Метод «Выбрать» очень сложен; у вас не может быть виртуальных шаблонных методов.

  template <typename T>
class Iterator {
public:
virtual ~Iterator() {};

// This is illegal, but if it weren't, it would be the functionality I want.
template <typename R>
virtual shared_ptr<IIterator<R>> Select(const function<R(T)>& func) = 0;

virtual shared_ptr<IIterator<T>> Where(const function<bool(T)>& func) = 0;
};

«Выбрать» позволит вам преобразовать итератор типа «сэндвич с ветчиной» в итератор типа «салат», например.

HamSandwiches-> Выбрать<‘Салат’> ​​([] (shared_ptr<‘HamSandwich’> hs) {return hs-> Салат; });

Игнорировать одинарные кавычки.

Поскольку у нас не может быть виртуальных шаблонных функций, я бы, конечно, не сделал эту функцию виртуальной. В этом случае у нас есть простая старая функция, которую мы никогда не должны «скрывать» ее реализацию, записывая реализации в List и Sequence по сравнению с виртуальной функцией; это будет считаться недостатком дизайна.

  template <typename T>
class Iterator {
public:
virtual ~Iterator() {};

template <typename R>
shared_ptr<Iterator<R>> Select(const function<R(T)>& func);

virtual shared_ptr<Iterator<T>> Where(const function<bool(T)>& func) = 0;
};

template <typename T>
template <typename R>
shared_ptr<Iterator<R>> Iterator<T>::Select(const function<R(T)>& func) {
//Implementation - What would it be?
}

Теперь у нас должна быть реализация в нашем базовом классе, которая должна быть несколько специфичной для List и Sequence. Из того, что я видел, вы начинаете создавать защищенные «функции реализации» для выполнения определенных действий в «Select», которые могут быть переопределены List или Sequence.

Я не ищу точного ответа здесь, я ищу что-то, что помогло бы мне достичь того, что я могу / должен хотеть быть. Кто-нибудь замечает какие-то распространенные ошибки или вещи, с которыми я могу ошибаться?

0

Решение

Опция 1

Идеи по реализации LINQ в C ++, которые я видел, совсем не основывались на виртуальных методах. Вместо этого каждый результат был возвращен в класс шаблона, примерно так:

template <class T>
class RangeWrapper
{
public:
template <class U>
Select(U u) -> decltype(...) {
return RangeWrapper<SelectRange, U>(_myRange, u);
}

private:
T& _myRange;
};

Если вы соедините несколько таких цепочек, тип возвращаемого значения может стать довольно большим, но это цена, которую нужно заплатить, чтобы все было сделано во время компиляции.

Вариант 2

Вы можете реализовать стирание типа, чтобы всегда возвращать итератор типа Iterator<T>, Этого должно быть довольно легко достичь с помощью библиотеки итераторов со стертыми типами в Интернете (есть много, вы можете взглянуть на boost.TypeErasure, который принят, но еще не выпущен).
В качестве альтернативы вы можете использовать any_range в boost, если вы в порядке для работы с диапазонами (они отображаются на LINQ более естественно, чем итераторы).

Вариант 3

Если вы не делаете это в качестве учебного упражнения, есть несколько решений, которые уже реализованы. Используйте Google. Следует отметить, что Microsoft сама работает над C ++ Linq для реализации реактивных расширений поверх него..

3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]