Подтвердить что ты не робот

У boost есть тип данных для заданных операций, который проще, чем STL?

Я нахожу метод С++ STL, делая простые операции с множеством, довольно неуклюжими в использовании. Например, чтобы найти разницу между двумя наборами:

std::set<int> newUserIds;
set_difference(currentUserIds.begin(), currentUserIds.end(), mPreviousUserIds.begin(), mPreviousUserIds.end(), std::inserter(newUserIds, newUserIds.end()));
std::set<int> missingUserIds;
set_difference(mPreviousUserIds.begin(), mPreviousUserIds.end(), currentUserIds.begin(), currentUserIds.end(), std::inserter(missingUserIds, missingUserIds.end()));
mPreviousUserIds = currentUserIds;

Поддерживает ли boost альтернативный набор классов, который сводит приведенный выше пример к следующему:

set_type<int> newUserIds = currentUserIds.difference(mPreviousUserIds);
set_type<int> missingUserIds = mPreviousUserIds.difference(currentUserIds);

(Аналогично QSet в Qt, который таким образом переопределяет operator-.)

4b9b3361

Ответ 2

Неа. Но я вот как его очистить.

Сначала перепишите функции, основанные на итераторе, как функции на основе диапазона. Это уменьшает ваш шаблон.

Во-вторых, им нужно вернуть конструкторы контейнеров, а не принимать итераторы вставки: это дает вам эффективный синтаксис присваивания.

В-третьих, и, возможно, слишком далеко, напишите их как названные операторы.

Конечный результат:

set<int> s = a *intersect* b;
set<int> s2 = c -difference- s;
set<int> s3 = a *_union_* (b *intersect* s -difference- s2);

... после написания лодку кода шаблона в другом месте.

Насколько я знаю, boost делает шаг 1.

Но каждый из этих трех этапов должен значительно уменьшить ваш шаблон.

Конструктор контейнеров:

template<typename Functor>
struct container_builder {
  Functor f;
  template<typename Container, typename=typename std::enable_if<back_insertable<Container>::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).

Вы завершаете функционал, основанный на диапазоне (или на основе итератора), который принимает back_insert_iterator в качестве последнего аргумента, и используйте std::bind для привязки входных параметров, оставляя последний доступным. Затем перейдите к container_builder и верните его.

container_builder затем может быть неявно передан в любой контейнер, который принимает std::back_inserter (или имеет свой собственный ADL back_inserter), а семантика move на каждом контейнере std делает конструкцию-то-возвращение довольно эффективной.

Вот моя дюжина строк с именем operator library:

namespace named_operator {
  template<class D>struct make_operator{make_operator(){}};

  template<class T, char, class O> struct half_apply { T&& lhs; };

  template<class Lhs, class Op>
  half_apply<Lhs, '*', Op> operator*( Lhs&& lhs, make_operator<Op> ) {
    return {std::forward<Lhs>(lhs)};
  }

  template<class Lhs, class Op, class Rhs>
  auto operator*( half_apply<Lhs, '*', Op>&& lhs, Rhs&& rhs )
  -> decltype( named_invoke( std::forward<Lhs>(lhs.lhs), Op{}, std::forward<Rhs>(rhs) ) )
  {
    return named_invoke( std::forward<Lhs>(lhs.lhs), Op{}, std::forward<Rhs>(rhs) );
  }
}

живой пример, используя его для реализации vector *concat* vector. Он поддерживает только один оператор, но его простота проста. Для серьезного использования я бы посоветовал иметь функцию times, которая по умолчанию вызывает invoke для *blah*, add для +blah+, которая делает то же самое и т.д. <blah> может напрямую вызвать invoke.

Затем клиентский программист может перегрузить специфическую для оператора перегрузку, и он работает, или общий invoke.

Вот аналогичная библиотека, используемая для реализации *then* как для функций возврата, так и для фьючерсов.

Вот примитив *in*:

namespace my_op {
  struct in_t:named_operator::make_operator<in_t>{};
  in_t in;

  template<class E, class C>
  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;

живой пример.

Ответ 3

Нет, и я думаю, что у этого никогда не было такого, это общий принцип в С++, который, когда вы можете иметь функцию, не являющуюся членом, чтобы выполнять работу, никогда не делает эту функцию членом. поэтому он не может быть таким, но может Boost:: Range помочь вам.