Czy boost ma typ danych dla operacji set, który jest prostszy niż STL?
Uważam, żemetoda C++ STL wykonywania prostych operacji setowych jest dość niewygodna w użyciu. Na przykład, aby znaleźć różnicę między dwoma zbiorami:
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;
Czy boost oferuje alternatywny zestaw klas, które zredukowałyby powyższy przykład do czegoś takiego:
set_type<int> newUserIds = currentUserIds.difference(mPreviousUserIds);
set_type<int> missingUserIds = mPreviousUserIds.difference(currentUserIds);
(podobny do QSet w Qt, który w ten sposób nadpisuje operator-
.)
3 answers
Zobacz algorytmy Boost Range Set . Nadal jednak oczekują iteratora wyjściowego.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-26 13:24:16
Nie. Ale tutaj jest jak to posprzątać.
Najpierw przepisz funkcje oparte na iteratorze jako funkcje dystansowe. To o połowę zmniejszy Twój kocioł.
Po drugie, niech zwracają konstruktory kontenerów zamiast iteratorów insert: daje to efektywną składnię przypisywania.
Po Trzecie, i prawdopodobnie za daleko, napisz je jako nazwane operatory.
Ostateczny wynik to:
set<int> s = a *intersect* b;
set<int> s2 = c -difference- s;
set<int> s3 = a *_union_* (b *intersect* s -difference- s2);
... po napisaniu boatload of boilerplate code gdzie indziej.
Z tego co wiem, boost robi krok 1.
Ale każdy z powyższych trzech etapów powinien znacznie zmniejszyć płytkę kotła.
Konstruktor kontenera:
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_) {}
};
Który wymaga napisania is_back_insertable
(dość standardowe SFINAE).
Owijasz swój funktor (lub oparty na iteratorze), który pobiera back_insert_iterator jako ostatni argument i używasz std::bind
, aby powiązać parametry wejściowe, pozostawiając ostatni wolny. Następnie przekaż to container_builder
i zwróć to.
container_builder
może być wtedy domyślnie rzucany do dowolnego kontenera, który akceptuje std::back_inserter
(lub ma swój własny ADL back_inserter
), a semantyka move
na każdym kontenerze std
sprawia, że construct-then-return jest dość wydajny.
Oto moja tuzin linii nazwanych biblioteką operatorów:
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) );
}
}
Przykład na żywo używanie go do implementacji vector *concat* vector
. Obsługuje tylko jednego operatora, ale jego rozszerzenie jest łatwe. W przypadku poważnego użycia radzę mieć times
funkcję, która domyślnie wywołuje invoke
dla *blah*
, an add
for +blah+
that does the same, etc. <blah>
może bezpośrednio zadzwonić invoke
.
Wtedy programista klienta może przeciążać specyficzne dla operatora przeciążenie i to działa, lub ogólne invoke
.
Oto podobna biblioteka używana do implementacji *then*
zarówno na funkcje zwracające krotki, jak i futures.
Oto prymitywne *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;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:22
Nie i myślę, że nigdy nie ma czegoś takiego, jest to ogólna zasada w C++ , że gdy możesz mieć funkcję nie-członkowską do wykonania zadania, nigdy nie rób z niej członka. więc nie może tak być, ale może być Boost::Range help you.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-26 13:25:27