I am sharing with you an issue that I got with a class using variadic function parameters. It is the class Thread shown in the following code. It is a wrapper of std::thread in order to use the function pattern.
I wanted to use polymorphism with this function in inheriting the class Thread into a new class, Functor, but gcc returns the errors bellow:
#include <thread>
#include <iostream>
using namespace std;
template<class... Args>
class Thread
{
public:
virtual void operator()(Args...) = 0;
void run(Args... args)
{
std::thread t(std::forward< Thread<Args...> >(*this), std::forward<Args>(args)...);
t.join();
}
};
template<class... Args>
class Functor : public Thread<Args...>
{
public:
// generates the errors bellow
virtual void operator()(Args... /*args*/)
{
}
// doesnot work since the pure virtual function wants another prototype of function.
// void operator()(int)
// {
// }
};
int main()
{
int a = 12;
Functor<int> f;
f.run(ref(a));
return 0;
}
from t-Thread-args2.cpp:1: /usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/tuple: In instantiation of ‘struct std::_Head_base, false>’: /usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/tuple:215:12: required from ‘struct std::_Tuple_impl, int>’ /usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/tuple:507:11: required from ‘class std::tuple, int>’ /usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/functional:1601:39: required from ‘struct std::_Bind_simple(int)>’ /usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/thread:133:9: required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = Thread; _Args = {int}]’ t-Thread-args2.cpp:14:83: required from ‘void Thread::run(Args ...) [with Args = {int}]’ t-Thread-args2.cpp:42:17: required from here /usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/tuple:166:13: error: cannot declare field ‘std::_Head_base, false>::_M_head_impl’ to be of abstract type ‘Thread’ t-Thread-args2.cpp:7:7: note: because the following virtual functions are pure within ‘Thread’: t-Thread-args2.cpp:10:18: note: void Thread::operator()(Args ...) [with Args = {int}]
I dont really understand the error since the pure virtual function was well defined in the deriveted class. However, in moving the function run() into the derivated class (Functor) it works.
Thanks in advance, Caner
As per [thread.thread.constr]§3, the type of the first argument of the std::thread
constructor is F&&
, with the requirement that F
is MoveConstructible
. In your case, F
is Thread
, which is not MoveConstructible
.
In other words, the std::thread
needs to store the functor by value, and you're forwarding the functor as Thread
, which is abstract.
The problem is:
std::forward< Thread<Args...> >(*this)
which tries to copy the Thread
sub-object. Luckily it's abstract, so you get a compile error rather than unexpected runtime behaviour.
You want a reference wrapper instead:
std::ref(*this)
I considered the multiple advice provided by the participants to this topic including the use of std::ref
and would like to share with you the working code version solving the issues I got with the previous code.
#include <thread>
#include <iostream>
using namespace std;
template<class... Args>
class Thread
{
public:
virtual void operator()(Args...) = 0;
void run(Args... args)
{
std::thread t(std::ref(*this), args...);
t.join();
}
};
template<class... Args>
class Functor : public Thread<Args...>
{
public:
void operator()(int)
{
while (1)
{
cout << "42 "; cout.flush();
}
}
};
int main()
{
int a = 12;
Functor<int> f;
f.run(ref(a));
return 0;
}
Thanks again.
来源:https://stackoverflow.com/questions/14996945/c-polymorphism-with-variadic-function-parameter