c++ algorithm reference stl c++17

c++ - ¿Hay una buena manera de asignar std:: minmax(a, b) a std:: tie(a, b)?



algorithm reference (3)

A veces, dar un paso atrás y encontrar una manera diferente da sus frutos:

if (b < a) std::iter_swap(&a, &b);

Eso es conciso y generalmente más eficiente, ciertamente al menos a la par. Tal vez empaquetarlo en su propia función:

template <class T> void reorder(T& a, T& b) noexcept(noexcept(b < a, void(), std::iter_swap(&a, &b))) { if (b < a) std::iter_swap(&a, &b); }

Estoy usando std::iter_swap() así que no tengo que usar el using std::swap; swap(a, b) using std::swap; swap(a, b) dos pasos para generalidad en pre-C ++ 2a, que introduce objetos de punto de personalización que lo hacen obsoleto.

std::tie(a, b) = std::minmax(a, b);

Creo que este es un código intuitivo. Limpio y comprensible. Lástima que no funcione según lo previsto, como las plantillas std::minmax para const& . Por lo tanto, si los valores se intercambian dentro del std::pair<const&, const&> una asignación sobrescribirá el otro valor:

auto[a, b] = std::make_pair(7, 5); std::tie(a, b) = std::minmax(a, b); std::cout << "a: " << a << ", b: " << b << ''/n'';

a: 5, b: 5

La salida esperada aquí es a: 5, b: 7 .

Creo que esto es importante ya que la implementación de funciones de transformación para aplicar una función en algunos rangos requiere tales declaraciones para lambdas intuitivas. Por ejemplo:

std::vector<int> v{ 0, 1, 0, 2, 0 }; std::vector<int> u{ 1, 0, 1, 0, 1 }; perform(v.begin(), v.end(), u.begin(), [](auto& a, auto& b){ std::tie(a, b) = std::minmax(a, b); }); //v would be == {0, 0, 0, 0, 0} //u would be == {1, 1, 1, 2, 1}

Una solución que encontré fue la construcción de un std::tuple explícitamente sin ningún calificador de referencia sobre el std::pair<const&, const&> para imponer una copia:

std::tie(a, b) = std::tuple<int, int>(std::minmax(a, b));

Pero esta redundancia <int, int> parece bastante horrible, especialmente cuando se dice antes auto& a, auto& b .

¿Hay una forma bonita y corta de realizar esta tarea? ¿Podría ser que esta es la dirección equivocada y solo decir if (a >= b) { std::swap(a, b); } ¿Sería el mejor enfoque aquí?


Puede aplicar esto con un cierto nivel de brevedad de la siguiente manera.

std::tie(a, b) = std::minmax(+a, +b); std::cout << "a: " << a << ", b: " << b << ''/n'';

Explicación: el operador integrado unary plus, en aras de la simetría con su hermano menos unario, devuelve su operando por valor (también realiza las conversiones aritméticas habituales, pero eso no se aplica a int s). Esto significa que tiene que crear un temporal, aunque este temporal no es más que una copia del operando. Pero para el uso de minmax en este ejemplo, es suficiente: intercambiar referencias aquí ya no se asigna, porque las referencias en el lado derecho (la const int& argumentos pasados ​​a minmax ) no se refieren a los mismos objetos que aquellos en el lado izquierdo (dentro de la tuple de referencias creadas por std::tie ).

La salida es la deseada:

a: 5, b: 7


Puedes usar una lista de inicialización para minmax :

std::tie(a, b) = std::minmax({a, b});

Esto hace que se creen objetos temporales, al igual que cuando se usa unary plus , pero tiene la ventaja de que funciona con los tipos que carecen del operador unary plus .

using namespace std::string_view_literals; auto [a, b] = std::make_pair("foo"sv, "bar"sv); std::tie(a, b) = std::minmax({a, b}); std::cout << "a: " << a << ", b: " << b << ''/n'';

Salida:

a: bar, b: foo

¿Podría ser que esta es la dirección equivocada y solo decir if (a >= b) { std::swap(a, b); } ¿Sería el mejor enfoque aquí?

Lo haría if(b < a) std::swap(a, b); debido al requisito de la Compare 1 , pero sí, sospecho que será más rápido y aún es muy claro lo que quiere lograr.

[1] Comparar [...] El valor de retorno de la operación de llamada de función aplicada a un objeto de un tipo que satisface la Comparación, cuando se convierte contextualmente a bool, produce verdadero si el primer argumento de la llamada aparece antes del segundo en el punto débil estricto Relación de orden inducida por este tipo, y en caso contrario falsa.