c++ - español - qgis girona
algoritmos estándar con puntero a miembro como comparador/"clave" (5)
¿Qué tal una vez que el operator<
sobrecarga operator<
para su tipo personalizado? Esto se puede hacer naturalmente dentro de la clase (o directamente junto a ella), y luego no se requieren argumentos adicionales al lado de los iteradores.
Pasar su función val()
no es posible, ya que debe pasar un operador binario.
EDITAR: Habiendo leído las otras alternativas valiosas (también la buena respuesta de Sehe), quiero confirmar lo que ya mencioné en el comentario a continuación: En mi opinión, nada supera la legibilidad, la localidad y también la flexibilidad de una expresión lambda (- en el riesgo de escribir algunos pasajes dos veces).
@Ryan Haining: te sugiero que lo guardes como en tu publicación original.
A menudo me encuentro usando std::sort
, std::max_element
y similares con un lambda que simplemente invoca una función miembro
std::vector<MyType> vec;
// populate...
auto m = std::max_element(std::begin(vec), std::end(vec),
[](const MyType& a, const MyType& b) { return a.val() < b.val()})
Esto se siente como un desperdicio de personajes y una pérdida de claridad. Soy consciente de que podría escribir otra función / llamable y pasar un indicador de función / objeto llamable a estas funciones de algoritmo, pero a menudo necesito hacer este tipo solo una vez en un programa y no me parece una buena opción. Manera de abordar el problema. Lo que quiero hacer, idealmente es decir:
auto m = std::max_element(std::begin(vec), std::end(vec), &MyType::val);
y tener los objetos ordenados por su val()
s. ¿Hay alguna parte de la norma que estoy pasando por alto que pueda ayudarme con esto? u otra forma simple de hacerlo? Me gustaría hacer que lo que se está clasificando o buscando sea lo más obvio posible.
Soy consciente de que solo &MyType::val
no es suficiente, estoy buscando algo que quizás pueda envolverlo, o proporcionar una funcionalidad similar sin entorpecer el significado.
Puede usar std::mem_fn
(o std::tr1::mem_fn
)
int main()
{
std::vector<MyType> vec;
auto m = std::max_element(std::begin(vec), std::end(vec), compare_by(std::mem_fn(&MyType::field)));
}
Por supuesto, esto supone que tienes una utilidad como compare_by
en tu caja de herramientas (como deberías :)):
template <typename F>
struct CompareBy {
explicit CompareBy(F&& f) : f(std::forward<F>(f)) {}
template <typename U, typename V>
bool operator()(U const& u, V const& v) const {
return f(u) < f(v);
}
private:
F f;
};
template <typename F>
CompareBy<F> compare_by(F&& f) { return CompareBy<F>(std::forward<F>(f)); }
Un comparador de plantillas podría ayudarte a:
template <typename StructureType,
typename MemberType,
MemberType StructureType::*member>
bool comparator(const StructureType& the_first, const StructureType& the_second)
{
return the_first.*member < the_second.*member;
}
Un poco de rasgos de tipo magia ciertamente podría permitirte evitar escribir el tipo.
Una mejora en la respuesta de la secuencia, para evitar la necesidad de usar std::mem_fn
sería proporcionar un puntero a la sobrecarga de miembros para la función compare_by
.
ejemplo de uso
std::sort(std::begin(vec), std::end(vec), compare_by(&MyType::field));
std::sort(std::begin(vec), std::end(vec), compare_by(&MyType::field, std::greater<>{}));
el código a implementar
#include <functional> // std::less
#include <utility> // std::move
#include <type_traits> // std::is_invocable_r
// Forward declaration
template<typename R, typename T, typename F = std::less<R>>
auto compare_by(R T::*, F = F{});
// Implementation
namespace detail {
template<typename T, typename F>
struct compare_by_t;
template<typename R, typename T, typename F>
struct compare_by_t<R T::*, F> : private F
{
compare_by_t(F&& f, R T::*m): F{std::move(f)}, _member{m} {}
R T::* _member;
bool operator()(T const& x, T const& y) const
{
return F::operator()(x .* _member, y .* _member);
}
};
} // detail
template<typename R, typename T, typename F>
auto compare_by(R T::* member, F f)
{
static_assert(std::is_invocable_r<bool, F, R, R>::value);
return detail::compare_by_t<R T::*, F>{ std::move(f), member };
}