Uso de Threads y error de compilación asignado a una libreria estandar...

Iniciado por digimikeh, 4 Agosto 2019, 00:58 AM

0 Miembros y 1 Visitante están viendo este tema.

digimikeh

Buenas..

Tengo este código y me está saliendo error, ppienso que la sintaxis está correcta.. aun no entiendo por qué el error..  Alguna pista?


Ver en el siguiente enlace el codigo para probar:
https://onlinegdb.com/ryO2ptQ7B

Saludos.


Edit : Le quite el simbolo de referencia en el parámetro para la funcion de la linea 5 y ahí compiló..
Pero no veo por qué...
Dungeons & dragons;
dragons.Attack();

Loretz

#1
...
CitarLe quite el simbolo de referencia en el parámetro para la funcion de la linea 5 y ahí compiló..
Pero no veo por qué...

Para poner las cosas más a mano, quitando de tu ejemplo lo que no viene al caso:
Código (cpp) [Seleccionar]
#include <iostream>
#include <thread>
#include <vector>

void f(std::vector<double>& vd) {
   for (auto& v : vd)
       std::cout << "From f -> " << v << std::endl;
}

int main() {
   std::vector<double> vd{ 2.5, 5.5, 7.1 };

   std::thread t0{ f, vd };      //<-- Error : No type named type in clas std::result_of))(std::vector&)> Si comento esta linea compila...

   t0.join();

   return 0;
}


Y dices que si quitas la referencia, si la función "f" toma su argumento por valor, entonces compila sin error. Está bien, y quisieras saber por qué...

Porque el constructor de thread que estás invocando es:
template< class Function, class... Args >
explicit thread( Function&& f, Args&&... args );

Ver: https://en.cppreference.com/w/cpp/thread/thread/thread

Y en ese caso, en las NOTAS, se aclara que
Citar"The arguments to the thread function are moved or copied by value. If a reference argument needs to be passed to the thread function, it has to be wrapped (e.g. with std::ref or std::cref). "

NO es que lo esté aclarando, sólo se dice que "Así debe ser",

Entonces, en tu ejemplo, podrías poner:

Código (cpp) [Seleccionar]
std::thread t0{ f, std::ref(vd) };

Funciona así porque std::ref devuelve ese wrapper que necesitas en el segundo argumento template, que se pasa por valor, pero se comporta como una referencia (encapsula, contiene, envuelve una referencia). https://en.cppreference.com/w/cpp/utility/functional/ref


Pero preguntabas "por qué".

Bueno, porque al construir la instancia de thread, en su constructor se invoca a la función del primer parámentro, con los parámetros del segundo parámetro, ¿de acuerdo?, pero esa llamada a f se hace a través de
Código (cpp) [Seleccionar]
std::invoke(decay_copy(std::forward<Function>(f)),
           decay_copy(std::forward<Args>(args))...);


Donde se invoca la función f con el "parameter pack" que devuelva "decay_copy", ¿verdad?

Pero esa "decay_copy" sólo hace un "forward" del pack que recibe, y devuelve a su vez un std::decay_t.

Y, ajá, acá está, es eso. Si te fijas en la documentación sobre std::dacay_t: https://en.cppreference.com/w/cpp/types/decay verás que para este caso:

Citarthe member typedef type is std::remove_cv<std::remove_reference<T>::type>::type.
These conversions model the type conversion applied to all function arguments when passed by value.

Ahorá sí, no sólo está aplicando std::remove_cv, que no tiene que ver con lo nuestro en este momento, sino que, fundamentalmente, aplica std::remove_reference al T::type que recibe como parámetro, que eso sí termina de explicar por qué necesitamos un wrapper cuando la función que se va a ejecutar en el nuevo thread toma sus parámetros por referencia.






Quise editar mi respuesta anterior y quedó una completa basura, así que escribo aquí a modo de apéndice:

Otra variante para considerar es que el parámetro de f sea una const reference:
void f(const std::vector<double>& vd)

o, como hay quien prefiere:
void f(std::vector<double> const& vd)
(con el "const" antes de &)