Кажется, что алгоритмы в диапазонах v3 не являются цепочечными, то есть:
const auto ints = std::vector<int>{1,2,1,3,1,4,1,5,1,6};
const auto num_ones = ints | ranges::count(1);
… Должен быть написан функциональный стиль:
const auto num_ones = ranges::count(ints, 1);
Является ли этот выбор дизайна тем, что только алгоритмы / действия, которые возвращают новый диапазон / контейнер, являются конвейерными?
Выход цепочечных представлений должен быть другим представлением (то есть диапазоном). Таким образом, вы можете продолжать цепочку результатов, используя больше представлений.
Результат count
это не диапазон, поэтому не имеет смысла включать эту операцию в цепочку. В гипотетическом случае, который вы могли бы сделать, вы не сможете связать результат этой операции с другим представлением.
Просмотр ситуации под другим углом, в диапазоне видимости v3 лениво оценивается. Подсчет количества элементов в диапазоне не является ленивой операцией, поскольку для получения результата требуется оценка всего диапазона. Это другой вид операции.
Те же рассуждения могут быть применены к другим «автономным» алгоритмам, таким как ranges::copy
, ranges::sort
, ranges::min_element
и т. д. Это следует рассматривать как варианты (или улучшения) соответствующих std
алгоритмы, но они также принимают диапазоны в качестве аргументов, а не пары итераторов.
С учетом вышесказанного, некоторые из автономных алгоритмов также доступны в виде представлений, где это имеет смысл (например, set_intersection
, set_difference
а также set_union
семейство алгоритмов).
редактироватьЕсть исключения из этого правила. А именно, функции ranges::to_vector
а также ranges::to_
которые «тонут» в диапазоне std::vector
(или контейнер по вашему выбору).
Некоторые алгоритмы на самом деле являются цепными, и вы можете найти их в пространстве имен view и / или action.
Но ваш код подсказывает, что у вас на самом деле другой вопрос. Почему нет алгоритмов с сигнатурой, позволяющих завершить цепочку труб? Я предлагаю пространство имен reducer
для таких алгоритмов. Вот пример рабочего кода:
#include <iostream>
#include <string>
#include <vector>
#include <range/v3/all.hpp>
using namespace std;
namespace view = ranges::view;
namespace action = ranges::action;
namespace reducer {
template <typename T>
class count {
T t;
public:
count(T t) : t(t) {}
template <typename Left>
T operator()(Left left) {
return ranges::count(left, t);
}
};
template <typename Left, typename T>
int operator|(Left left, count<T> right) {
return right(left);
}
}
int main (int argc, char * argv[])
{
const auto ints = std::vector<int>{1,2,1,3,1,4,1,5,1,6};
const auto num_ones = ints | reducer::count(1);
cout << num_ones << endl;
return 0;
}
Эрик Ниблер сказал, что люди выкидывают из бедра много идей, как и мы, но не видят глубоких последствий. Так что, возможно, в этой идее есть что-то плохое, чего мы не видим. Было бы здорово, если бы он прошел мимо вашего вопроса и просветил нас комментарием.
Конечно, он использовал C ++ 11 для range-v3 и без определения типа для конструкторов эту идею сложнее реализовать.