Compiler error C2440, and pretty strange and uncomprehensible text in it !
Now that i have caought your attention, i will show you that as a matter of fact there is something strange MSVC++ 7.0 tells me, but first the code:
I have a class that dispatches threads, in such a fashion, that it is possible for a thread to run a foreign object's member function. For example you have a thread object "thread obj1" and an object "datafeed obj2". "thread" class has a constructor which runs any member function (void parameters) of any other class, here "datafeed" asynchroniously (in context of parallel thread). Practically i am having problems here:
Code:
class thread
{
template<class T, DWORD (T::*pMember)()> friend DWORD WINAPI callFunctor(LPVOID pObj)
{
return (((T*)pObj)->*pMember)();
}
HANDLE hThread;
DWORD threadID;
public:
class createThreadFailed {};
template<class T> thread(T* pObj, DWORD (T::*pMember)())
{
DWORD (WINAPI *pThreadProc)(LPVOID pParam) = callFunctor<T, pMember>;
hThread = CreateThread(NULL, 0, pThreadProc, pObj, 0, &threadID);
if(!hThread) throw createThreadFailed();
}
};
THe code is extracted from a valid C++ header, but in order for it to be readable i changed it a bit, thrown out unneded functions etc. So please take it with a grain of salt, however, the precise structure of the idea is present in it.
Basically thread object constructor receives parameters of an object, and a member, which together form a callable entity (member) which the new thread will run.
The problem is, that i get this compiler error:
"error C2440: 'initializing' : cannot convert from 'DWORD (__stdcall *)(LPVOID)' to 'DWORD (__stdcall *)(LPVOID)'
None of the functions with this name in scope match the target type
example.cpp(27) : see reference to function template instantiation 'thread::thread(T *,DWORD (__thiscall dataFeed::* )(void))' being compiled
with
[
T=dataFeed
]"
Isn't it funny how compiler cant convert from the same type to the same type ?
I am not one who gives up easily, so I actually had tried some options. For instance, since templates are instantiated at compile time, a constant template parameter is required, and hence passing a function parameter further as a template parameter wouldn't work. So i actually tried to use member pointer as a 'const' in the constructor, but then other kind of errors show up. I also tried to make member address a template parameter instead of constructor parameter, but then MSVC++ doesn't welcome template constructors in non-template classes. The last option that i DONT WANT TO TRY is substiting thread parameter with a functor instead of a sole object pointer, and thus avoiding to pass member function address all together. This is all i got on my hands. Could you help me with the first two options ? I dont want to choose other solution, because if it is possible to get either of the two to work, they seem a very elegant way.
Thanks in advance !
I think i made a decision after so many helpful suggestions ..
I can't believe you have done so much work, helping me, galathea :) If there is anything you need, i own it to you ! ;)
Thank you, this is indeed tremendeously helpful, only the idea you presented is worth its amount of lines in golden bars alone !!!
You see, I in fact have made almost identical code to the one you present, when first approached my problem. I had also a functor class which i did pass as a parameter to thread routine. THe thing is, you are of course right, what to do with this functor when it is no longer needed, and when to do it ?
I have to guarantee that the caller thread maintains a valid functor object that the new thread routine receives via its sole parameter, and that it does not go out of scope before the new thread catches it. This is possible, as you did, through dynamic allocation, and i think a good idea would be then to delete the functor in fact, in the new thread somewhere before everything else kicks in:
Code:
template <class T>
DWORD WINAPI functor(LPVOID pFunctor)
{
T* pObj = ((functor<T>*)pFunctor)->pObj;
DWORD (T::*pMember)() = ((functor<T>*)pFunctor)->pMember;
delete pFunctor; //at last !
return (pObj->*pMember)();
}
Well, what you think ? I personally think it is too much trouble coverup for the sorry absense of possibility to explicitly pass template parameters to constructor templates in C++...Another thing is, probably good, in a way, is that this approach above allows for dynamic functors, and thus threads that can decide which member functions to run at run-time, unlike templated approach, which only allows to generate c++ code with already arranged types. And I in fact, don't need run-time functors, templates were what i wanted (wuaaaaaaaa!!).
But ! You helped me a lot ! Don't think I didn't benefit from your sincere help, your work was not in vain !!! Thanks a lot, i just looked over many possible solutions, including your two, and I decided i just make a template "create" function instead of constructor, until new C++ draft is available ! :D
Thanks ! See you around...