Ordenación paralela con std::sort y un iterador personalizado convierte valores
Estoy escribiendo un método de ordenamiento que ordena dos arreglos simultáneamente, basado en los valores de uno de los arreglos. Usé esto como referencia y hice algunos cambios menores (hice que el operador *()
sea constante y agregué constructores para la clase ref
), por lo que compila en MSVC/g++/clang.
Después de agregar std::execution::par
para habilitar la ordenación paralela, clang y g++ ya no lo compilan (pero MSVC sí). El código final y el error se pueden encontrar aquí. Los errores en g++ y clang son similares:
source:45:6: note: candidate function not viable: no known conversion from ‘const val’ to ‘const ref’ for 1st argument
bool operator<(ref const& a, val const& b)
Este error se puede resolver implementando bool operator<(val const& a, val const& b)
, pero luego el arreglo de valores finales retiene cadenas vacías. Esto se puede solucionar eliminando el operador move
de operator val() &&
. Sin embargo, el operador move
fue una importante decisión de diseño para el rendimiento.
Pregunta: ¿Hay alguna manera de mantener el operador move
?
Ahora compila en el entorno en línea de godbolt.org, pero no localmente, porque la instalación de tbb afecta los pasos de compilación. Tbb está instalado localmente y es necesario para la ejecución paralela real. El error es:
/usr/include/c++/9/pstl/parallel_backend_tbb.h:435:1: required from here
/usr/include/c++/9/bits/predefined_ops.h:215:11: error: no match for call to ‘(std::less
215 | { return bool(_M_comp(__val, *__it)); }
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/c++/9/string:48,
from tmp.cpp:2:
/usr/include/c++/9/bits/stl_function.h:385:7: note: candidate: ‘constexpr bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = val]’
385 | operator()(const _Tp& __x, const _Tp& __y) const
| ^~~~~~~~
/usr/include/c++/9/bits/stl_function.h:385:7: note: conversion of argument 1 would be ill-formed:
In file included from /usr/include/c++/9/bits/stl_algobase.h:71,
from /usr/include/c++/9/vector:60,
from tmp.cpp:1:
/usr/include/c++/9/bits/predefined_ops.h:215:11: error: invalid user-defined conversion from ‘const ref’ to ‘const val&’ [-fpermissive]
215 | { return bool(_M_comp(__val, *__it)); }
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
tmp.cpp:42:2: note: candidate is: ‘ref::operator val() &&’
42 | operator val() && { return {*key, *value}; }
| ^~~~~~~~
tmp.cpp:42:2: note: passing ‘const ref’ as ‘this’ argument discards qualifiers
Pregunta adicional: ¿Por qué quiere hacer una conversión si puede usar bool operator<(ref const& a, ref const& b)
?
davy.ai
Como experto en IT especializado en C++, específicamente en C++17, puedo brindar la siguiente respuesta:
Para mantener el operador de traslado, es necesario implementar
bool operator<(val const& a, ref const& b)
. Esto permitirá la comparación del tipo de valorval
con el tipo de referenciaref
. La razón por la que el operadormove
estaba causando cadenas vacías en el array de valores finales es porque el operadormove
estaba transfiriendo la propiedad de la cadena, dejando el objeto original vacío.En cuanto a la pregunta complementaria, el error se produce porque el
operator<
que se llama espera un objetoval
como primer argumento en lugar de un objetoref
. El error de conversión se produce porque no hay una conversión válida deconst ref
aconst val&
para el primer argumento. Si bien hay una implementación debool operator<(ref const& a, ref const& b)
disponible, no se puede utilizar en este caso porque el primer argumento esperado por el operador de comparación esconst val&
.