I have variadic template class representing a thread with function and input arguments.
template<typename F> class my_thread;
template<typename Return, typename... Input>
class my_thread<Return(Input...)>
{
template<typename F>
my_thread(F&& f, Input&&... value) : /* mainly std::forward<Input>... to std::tuple<Input...> */ { }
}
Now, instancing that class is simple for global functions
int fnc(int, double);
my_thread<int(int, double)> thr(fnc, 42, 3.14);
It is (obviously) not that simple for function members of some class.
my_thread<int(int, double)> thr(&Foo::fnc, 42, 3.14); // won't work, unless Foo::fnc is static.
I know, that std::thread
, has some mechanics (probably partial specialization), which allows non-static member functions to be passed, if, before all arguments, pointer to instance of that class is passed (std::thread(&Foo::bar, Foo(), 42, 3.14); // OK
). I was not able to find out how to make that happen, so my my_thread
requires static member functions to be passed, and pointer to instance of that class has to be excplicit argument of that function.
struct Dog
{
void bark();
static void bark(Dog* dog)
{
dog->bark();
}
}
That is something I have to live with, but that is not problem.
Problem is instantiating my_thread
with that function. I wrote my_thread<int(Foo*, double)> thr(&Foo::bar, this, 3.14);
into Visual Studio 2015 and it complained about
error C2664: 'my_thread<int (Foo *, double)>::my_thread(my_thread<int (Foo *, double)> &&)': cannot convert argument 2 from 'Foo *const ' to 'Foo *&&'
I tried some magic with casting, but then, I found out, that passing &*this
instead of this
works.
I was happy to find out solution (or at least something that compiles and runs on Windows) and I decided to try it on linux with G++. I used same code (using &*this
), but G++ was angry at me, because
In member function 'void Foo::SomeFunction()': error: no matching function for call to ‘my_thread<int(Foo*, double)>::my_thread(int (*)(Foo*, double), Foo* const, double&)’
note: candidates are: my_thread(F&&, Input&&...)
note: template argument deduction/substitution failed:
note: cannot convert ‘this’ (type ‘Foo* const’) to type ‘Foo*&&’
I was quite surprised that I got pretty much same error as before. I edited back &*this
to just this
and I was able to compile and run that on G++ under linux.
My question is:
Who is right? G++ 4.9.2 or MVS2015? How do I solve it, so that my code can be run on both platforms?
Or, am I using bad approach to that? How is std::thread implemented, such that it knows, that when non-static member function is passed, it will require pointer to instance of that class as an argument?
EDIT
I am adding more code, so that my intention will be clearer.
template<typename F> struct my_thread; // std::function like syntax
template<typename Return, typename... Input>
struct my_thread<Return(Input...)>
{
struct thread_data
{
template<typename F>
thread_data(F&& _func, Input&&... _input) : func(std::forward<F>(_func)), input(std::forward<Input>(_input)...) { }
std::function<Return(Input...)> func;
std::tuple<Input...> input;
};
template<typename F>
my_thread(F&& _func, Input&&... _input) : data(std::forward<F>(_func), std::forward<Input>(_input)...) { }
thread_data data;
};