¿El impulso tiene un tipo de datos para operaciones de conjunto que es más simple que el STL?

Encuentro que el método C ++ STL de hacer operaciones simples es bastante complicado de usar. Por ejemplo, para encontrar la diferencia entre dos conjuntos:

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; 

¿Impulso ofrece un conjunto alternativo de clases que reduciría el ejemplo anterior a algo como esto:

 set_type newUserIds = currentUserIds.difference(mPreviousUserIds); set_type missingUserIds = mPreviousUserIds.difference(currentUserIds); 

(Similar a QSet en Qt, que anula al operator- de esta manera).

Ver los algoritmos del conjunto de rango Boost . Sin embargo, todavía esperan un iterador de salida.

Nop. Pero aquí es cómo limpiarlo.

Primero, vuelva a escribir las funciones basadas en iterador como funciones basadas en rangos. Esto reduce a la mitad tu repetición.

Segundo, pídales que devuelvan constructores de contenedores en lugar de tomar iteradores de inserción: esto le brinda una syntax de asignación eficiente.

En tercer lugar, y probablemente demasiado lejos, escríbalos como operadores con nombre.

El resultado final es que obtienes:

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

… después de escribir un bote de código repetitivo en otro lugar.

Por lo que sé, el impulso hace el paso 1.

Pero cada una de las tres etapas anteriores debería reducir significativamente tu repetición.

Constructor de contenedores:

 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_) {} }; 

que requiere escribir is_back_insertable (bastante estándar SFINAE).

Envuelve su functor basado en rangos (o basados ​​en iteradores) que toma un back_insert_iterator como el último argumento, y usa std::bind para enlazar los parámetros de entrada dejando el último libre. Luego pasa eso a container_builder , y regresa.

container_builder puede convertir implícitamente en cualquier contenedor que acepte std::back_inserter (o tenga su propia ADL back_inserter ), y move semántica en cada contenedor std hace que la construcción-luego-retorno sea bastante eficiente.

Aquí está mi docena de línea llamada biblioteca de operador:

 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) ); } } 

ejemplo en vivo usándolo para implementar vector *concat* vector . Solo es compatible con un operador, pero extenderlo es fácil. Para un uso serio, te aconsejo que tengas una función de times que invoke de manera predeterminada para *blah* , un add para +blah+ que haga lo mismo, etc. puede invoke directamente a invoke .

Entonces el progtwigdor del cliente puede sobrecargar una sobrecarga específica del operador y funciona, o la invoke general.

Aquí se está utilizando una biblioteca similar para implementar *then* en ambas funciones y futuros de devolución de tupla.

Aquí hay un primitivo *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; 

ejemplo en vivo

No, y creo que nunca tiene algo así, este es un principio general en C ++ que dice que cuando puedes tener una función no miembro para hacer el trabajo, nunca hagas que esa función sea miembro. entonces no puede ser así, pero puede ser que Boost :: Range lo ayude.