Once again I need your help making std::thread
work with templated objects. This time my issue is in one of the arguments.
I try passing a reference to a (valid) instantiation of a virtual class as one of the arguments of my thread, and it just doesn't work. Note that passing a pointer instead of a reference solves everything. But still, why can't I give a reference (which I prefer, for many reasons)
Small code reproducing my error :
#include <cstdio>
#include <thread>
#include <vector>
template<typename T>
class functor { public: virtual T operator()(T) const = 0; };
template<typename T>
class square : public functor<T>
{
public:
T operator()(T f) const { return f*f; }
};
template<typename T>
void thread(const functor<T>& func, size_t imin, size_t imax) // line1
{
for(size_t i=imin; i<imax; ++i)
{
T arg = T(i);
std::cout << arg << "=>" << (func)(arg)) << std::endl; // line2
}
}
template<typename T>
void threadlauncher(const functor<T>& func, size_t imin, size_t imax, size_t nbthread)
{
size_t window = (imax-imin)/nbthread + ((imax-imin)%nbthread?1:0);
std::vector<std::thread> threads;
for (size_t idthread=0; idthread<nbthread; ++idthread)
{
size_t tmin = std::min(window*(idthread+0), imax);
size_t tmax = std::min(window*(idthread+1), imax);
threads.push_back(
std::thread(&thread<T>, func, tmin, tmax) // line3
);
}
for (std::thread& thread : threads)
thread.join();
}
int main()
{
square<float> func;
threadlauncher<float>(func, 0, 10, 3);
return 0;
}
The compiler (gcc 4.9.2) tells me that my object is invalid because operator()
is virtual in threadlauncher
Note that changing code to pass thread's argument using pointers solves this
void thread(const functor<T>* func, size_t imin, size_t imax) // line1
std::cout << arg << "=>" << (*func)(arg)) << std::endl; // line2
std::thread(&thread<T>, &func, tmin, tmax) // line3
How can I make him understand that my reference is valid ?
Edit
I get an long/unreadeble error message from the compiler. I guess the important part is
src/functorthreads.cc:50:38: required from here
/usr/include/c++/4.9.2/functional:1713:9: erreur: invalid abstract parameter type ‘functor<float>’
__type;
^
src/functorthreads.cc:6:7: note: because the following virtual functions are pure within ‘functor<float>’:
class functor
^
src/functorthreads.cc:9:13: note: T functor<T>::operator()(T) const [with T = float]
virtual T operator()(T) const = 0;
std::thread
takes copies of it's arguments. It doesn't matter that the argument to the function is a reference....thethread
constructor will still copy the arguments since they are being passed to another thread. That's why pointers work, since they are being copied.If you know that your object will remain in scope throughout the lifetime of the thread, you can use
std::ref
to wrap your argument: