C ++ имеет свободные функции, но иногда методы расширения работают лучше, когда вы вкладываете много функций вместе. Посмотрите на этот код C #:
var r = numbers.Where(x => x > 2).Select(x => x * x);
Если мы напишем это в C ++, используя свободную функцию, это будет выглядеть так:
auto r = select(where(numbers, [](int x) { return x > 2; }), [](int x) { return x * x; });
Мало того, что это трудно читать, но и трудно писать. Обычный способ решить эту проблему - создать так называемую функцию. Эти функции создаются путем перегрузки оператора канала |
(который на самом деле является оператором or). Таким образом, приведенный выше код может быть написан так:
auto r = numbers | where([](int x) { return x > 2; }) | select([](int x) { return x * x; });
Что гораздо проще читать и писать. Многие библиотеки используют функцию pipable для диапазонов, но ее можно расширить и на другие классы. Boost использует его в своей библиотеке range , pstade духовка использует его, а также эта библиотека C ++ linq также использует его.
Если вы хотите написать свою собственную переносимую функцию, boost объяснит, как это сделать здесь . Другие библиотеки, однако, предоставляют функциональные адаптеры, чтобы упростить его. Pstade egg имеет адаптер для трубопровода , а linq предоставляет адаптер range_extension
для создания функции трубопровода для диапазонов как минимум.
Используя linq, вы сначала создаете свою функцию как функциональный объект, подобный этому:
struct contains_t
{
template<class Range, class T>
bool operator()(Range && r, T && x) const
{ return (r | linq::find(x)) != boost::end(r); };
};
Затем вы инициализируете функцию с помощью статической инициализации следующим образом:
range_extension<contains_t> contains = {};
Тогда вы можете использовать свою функцию pipable следующим образом:
if (numbers | contains(5)) printf("We have a 5");