У boost есть тип данных для заданных операций, который проще, чем STL?
Я нахожу, что метод C ++ STL делает простые операции с множеством, довольно неуклюжими в использовании. Например, чтобы найти разницу между двумя наборами:
std::set newUserIds; set_difference(currentUserIds.begin(), currentUserIds.end(), mPreviousUserIds.begin(), mPreviousUserIds.end(), std::inserter(newUserIds, newUserIds.end())); std::set missingUserIds; set_difference(mPreviousUserIds.begin(), mPreviousUserIds.end(), currentUserIds.begin(), currentUserIds.end(), std::inserter(missingUserIds, missingUserIds.end())); mPreviousUserIds = currentUserIds;
Повышает ли предложение альтернативный набор classов, который сводит приведенный выше пример к чему-то вроде этого:
set_type newUserIds = currentUserIds.difference(mPreviousUserIds); set_type missingUserIds = mPreviousUserIds.difference(currentUserIds);
(Аналогично QSet в Qt, который переопределяет operator-
таким образом.)
- Какой контейнер STL следует использовать для FIFO?
- Как читать растущий текстовый файл на C ++?
- «Правильный» способ хранения двоичных данных с помощью C ++ / STL
- C ++ Стереть векторный элемент по значению, а не по положению?
- Почему я не могу push_back unique_ptr в вектор?
- Должен ли я хранить целые объекты или указатели на объекты в контейнерах?
- вектор или карту, какой из них использовать?
- std :: fstream не создает файл
- std :: string :: c_str () и временные
- Спецификация шаблона Функция перегрузки функций VS
- Почему контейнеры STL не имеют виртуальных деструкторов?
- Почему сохранение ссылок (не указателей) в контейнерах на C ++ не работает?
- Получение вектора в функцию, которая ожидает вектор
См. Алгоритмы установки диапазона усиления . Однако они все еще ожидают выходного iteratorа.
Неа. Но я вот как это очистить.
Во-первых, перепишите функции на основе iteratorа как функции на основе диапазона. Это уменьшает ваш шаблон.
Во-вторых, им нужно вернуть конструкторы контейнеров, а не принимать iteratorы вставки: это дает вам эффективный синтаксис присваивания.
В-третьих, и, возможно, слишком далеко, напишите их как названные операторы.
Конечным результатом является то, что вы получаете:
set s = a *intersect* b; set s2 = c -difference- s; set s3 = a *_union_* (b *intersect* s -difference- s2);
… после написания лодочного кода шаблона в другом месте.
Насколько я знаю, boost делает шаг 1.
Но каждый из этих трех этапов должен значительно уменьшить ваш шаблон.
Контейнерный строитель:
template struct container_builder { Functor f; template ::value>::type> operator Container() const { Container retval; using std::back_inserter; f( back_inserter(retval) ); return retval; } container_builder(Functor const& f_):f(f_) {} };
который требует записи is_back_insertable
(довольно стандартный SFINAE).
Вы завершаете функционал, основанный на ранжировании (или на основе iteratorа), который принимает back_insert_iterator в качестве последнего аргумента и использует std::bind
для привязки входных параметров, оставляя последний доступным. Затем передайте это container_builder
и верните его.
container_builder
затем может быть неявно применен к любому контейнеру, который принимает std::back_inserter
(или имеет свой собственный ADL back_inserter
), и move
семантики на каждом контейнере std
делает конструкцию-then-return довольно эффективной.
Вот моя дюжина строк с именем operator library:
namespace named_operator { templatestruct make_operator{make_operator(){}}; template struct half_apply { T&& lhs; }; template half_apply operator*( Lhs&& lhs, make_operator ) { return {std::forward(lhs)}; } template auto operator*( half_apply&& lhs, Rhs&& rhs ) -> decltype( named_invoke( std::forward(lhs.lhs), Op{}, std::forward(rhs) ) ) { return named_invoke( std::forward(lhs.lhs), Op{}, std::forward(rhs) ); } }
живой пример, использующий его для реализации vector *concat* vector
. Он поддерживает только один оператор, но его простота проста. Для серьезного использования я бы посоветовал иметь функцию times
которая по умолчанию вызывает invoke
для *blah*
, add
for +blah+
который делает то же самое, и т. Д.
может напрямую вызывать invoke
.
Затем клиентский программист может перегрузить специфическую для оператора перегрузку, и он работает, или общий invoke
.
Вот аналогичная библиотека, используемая для реализации *then*
на обеих возвращающих функции и фьючерсах.
Вот примитив *in*
:
namespace my_op { struct in_t:named_operator::make_operator{}; in_t in; template bool named_invoke( E const& e, in_t, C const& container ) { using std::begin; using std::end; return std::find( begin(container), end(container), e ) != end(container); } } using my_op::in;
живой пример .
Нет, и я думаю, что у этого никогда не было такого, это общий принцип в C ++, который, когда вы можете иметь функцию, не являющуюся членом, чтобы выполнять работу, никогда не делает эту функцию членом. так что это не может быть так, но может быть Boost :: Range помочь вам.