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:
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.
Try to perform an EXPLICIT typecating to the function-address argument what CreateThread expectes. Like:
CreateThread(NULL,0,(CALLBACK)pThreadProc,pObj,0,&threadID);
Where 'CALLBACK' be the datatype.
Amn
April 22nd, 2003, 07:19 AM
I figured it out, well at least the error part of it.
What is happening is that i cannot pass an address of a local variable as a template argument (duh!), and the real error is:
error C2971: 'h::win32::callFunctor' : template argument 'pMember' : invalid use of local variable 'pMember' as non-type argument
When i substituted the body of constructor with this simple line:
callFunctor<T, pMember>(pObj);
the real error showed up.
So, now i have another problem, which is:
template<class T, DWORD (T::*pMember)() > thread(T* pObj)
{
callFunctor<T, pMember>(pObj); //just an example dummy really
}
It turns out that i cannot instantiate constructor templates of non-template classes (thread, in this case). I really need a non-template regular class type, and i really need constructor template.
I tried this:
thread obj<A, A::f>(&obj);
but i am getting error:
error C2143: syntax error : missing ';' before '<'
So how do i do it ? :)
Ajay Vijay
April 22nd, 2003, 07:59 AM
Sorry! I am not well exprienced with templates (atleast not aby better than your sound concepts)!
Gabriel Fleseriu
April 22nd, 2003, 08:29 AM
I didn't take much time to look at your code, but:
1. ISO/IEC 14882, 14.5.2/5:
Note: because the explicit template argument list follows the function template name, and
because conversion member function templates and constructor member function templates are called without
using a function name, there is no way to provide an explicit template argument list for these function Member templates.
2.
callFunctor<T, pMember>(pObj); //just an example dummy reallypMember isn't a DWORD.
Amn
April 22nd, 2003, 08:43 AM
Thank you !
Gabriel, with ISO reference, are you referring to the constructor template code being used improperly, or are you referring to the callFunctor instantiation (quoted in your reply)? Because instantiation of callFunctor works perfectly fine, i just cant seem to find a way to create an object of the class with my constructor template... :)
In other words, are you saying that callFunctor related code is alright, but i can't use constructor templates with non-template classes because "there is no way to provide an explicit template argument list for these function Member templates." ?
Sorry, i explain my ideas badly sometimes, but god, do i try !
2. pMember is DWORD ? isn't it ? its a member pointer to a function that returns a DWORD ? You mean it should be DWORD, but is not ? Where is it NOT DWORD then ? too complicated.. ;)
Gabriel Fleseriu
April 22nd, 2003, 08:55 AM
I understand the note in the ANSI like this: you cannot have a template ctor or conversion operator.
About pMember not being a DWORD: my mistake, I didn't read you first post correctly, sorry :)
galathaea
April 22nd, 2003, 09:25 AM
Well... you can have a parametrized ctor, its just that ctors do not have names and do not undergo normal lookup, so you cannot name which ctor to call through a parameter list or any other naming scheme. Instead, you are left to specifying which ctor to call through the ctor function parameters. You can template over these, and there is some very interesting code that takes advantage of this (for example boost.any uses a parametrized ValueType to identify and "store" the type found in the holder class). So I would just suggest either moving the typing over to a ctor parameter or separating out construction and initialization (though that's never pretty).
Additionally it looks like Amn is trying to pass a member function instance as a template parameter instead of a member function type. Member functions are not legitimate non type parameters to templates, so the interface needs to be patched up a little. Maybe taking a look at the code to the STL member function binders or Loki's Functor implementation (of course, it wouldn't take me long to mention him :)) can help clear up the possibilities for such an interface.
Amn
April 22nd, 2003, 09:47 AM
Gabriel, thank you for your HELPFUL reply. You pointed out the very root of the issue ! It was enough of me then to lookup 14.5.2/5 in ISO draft, and everything is clear to me now. As you and galathea point out, there is no way to send an explicit template parameter to a ctor or conversion function. So let it be then.
Galathea, first, nice to see you again. I ve been absent for halv a year actually, and its fun to see you again !!!
Anyway, yes, i am aware that you cannot send local variables as template parameters, and since then my code is altered so that ctor receives needed parameters in needed places (pMember as a template argument and not a ctor argument). Still a problem of creating an object with parameterized ctor seems to be unsolvable easily.
No, i dont want to separate construction and initialisation, my whole library is based on exceptions, and error checking is done under the hood, everything should be light, and without ".create" functions :) But of course i have to change course, if it turns out to be impossible to do what i am trying to do here..Still, last option only !
Can you tell me just a bit more about Boost's approach to ctor template instantiation with explicit parameters ? If i understood correctly, you said it can be done ?
galathaea
April 22nd, 2003, 10:07 AM
It's great to see you back too, Amn! I only hope your absence was due to vacation and not overloading with work!
About the parameterized ctors... You just need to make function parameters for the things you want.
In other words:
template<class SomeType>
SomeClass(SomeType* pObj, DWORD (SomeType::*pMember)())
{
// Do the ctor initialization with the parameters here
}
In other words, it really looks like you may need to move the template parameter for the member function to the parameter list so that an instance can be passed, and as is you don't need anything else as a template parameter. If you want to allow different member function signatures (maybe it allows returns other than DWORD or different parameters can be passed) just add a template parameter like "class MemFunction" which allows you to specify the type (the type of the above member function is DWORD (SomeType::*)() with no pMember name, which is how it should be passed as a template parameter) and still pass the actual instance as a parameter.
(breathe)
So... is that what you are looking for?
Amn
April 22nd, 2003, 10:20 AM
Yes precisely ! But it is not easy to jump from template parameter to ctor parameter...you see, i pass the pMember further on to ANOTHER TEMPLATE, and in case of ctor parameter, i end up trying to pass a non legitimate type to "functor" template. That is why i need it explicitly in template, unless YOU ;) explain ME , what was your idea with using nested templates (templating the DWORD attribute). I am interested in that approach !!! Help out on this one please, i cant think nested templates !!! ;|
Basically this is a thread class that dispatches foreign members asynchrouniously and still behold the data in its members.
galathaea
April 22nd, 2003, 12:07 PM
I think to get things working will require a little restructuring, since you are trying to use a member function instance name as a template parameter instead of a member function type name. Maybe something like this quick and ugly workaround will work:
Its ugly in my eyes because now you have to deal with lifetime management of myFunctor. I would suggest fixing it up by making myFunctor a member variable and cleaning up in the dtor or, better yet, using your favorite smart pointer to wrap it up (still a member variable) to automatically manage cleanup. I am fairly sure that VC++ 7.0 (aka .NET) can handle the function template without the type as a parameter (since you need the LPVOID to match the thread function signature), but if not, you can use explicit casts here (eww...) as a workaround. And it is of course possible and better to wrap up things with better encapsulation, but its hard for me to make a test project to get this working without knowing better how the thread class will be used. In this form, you create the thread class by passing both the object and the member function as parameters to the thread class' construction (without any template remnants, like the <> brackets). The compiler should handle the rest.
Let me know how this works, as I haven't tested this particular code. I have used something slightly similar, though, for other callback-type mechanism, but my code for such are slightly different as I use library functors with binding. But this is the basic mechanism, as far as I can tell...
galathaea
April 22nd, 2003, 01:09 PM
I must appologize for some stupid errors in the code I previously posted. In particular, the operator() needs a second set of parentheses, ie. the parameter list. Also, I tend to prefer certain other calling conventions and c++ style casts. So I made a completely ugly test project in vc++.net and debugged to the point of getting it to work (albeit with resource and memory leaks because I was lazy). Here is a full test project to work with:
int main()
{
DummyClass *myDummy = new DummyClass;
thread *myThread = new thread(myDummy, DummyClass::DummyFunction);
Sleep(5000);
}
I regret the bad coding style that this presents, and it is obviously not thread safe (it could end before the thread executes), but it is really only illustrative, so please take it with a grain of salt ;).
Amn
April 22nd, 2003, 02:11 PM
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:
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...
codeguru.com
Copyright Internet.com Inc., All Rights Reserved.