CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 14 of 14
  1. #1
    Join Date
    May 2001
    Location
    Oslo, Norway
    Posts
    610

    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 !
    Last edited by Amn; April 22nd, 2003 at 06:46 AM.

  2. #2
    Join Date
    Mar 2003
    Location
    India {Mumbai};
    Posts
    3,871
    Code:
    hThread = CreateThread(NULL, 0, pThreadProc, pObj, 0, &threadID);
    Try to perform an EXPLICIT typecating to the function-address argument what CreateThread expectes. Like:
    Code:
    CreateThread(NULL,0,(CALLBACK)pThreadProc,pObj,0,&threadID);
    Where 'CALLBACK' be the datatype.
    My latest article: Explicating the new C++ standard (C++0x)

    Do rate the posts you find useful.

  3. #3
    Join Date
    May 2001
    Location
    Oslo, Norway
    Posts
    610
    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:

    Code:
    callFunctor<T, pMember>(pObj);
    the real error showed up.

    So, now i have another problem, which is:

    Code:
    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:

    Code:
    thread obj<A, A::f>(&obj);
    but i am getting error:

    error C2143: syntax error : missing ';' before '<'


    So how do i do it ?
    Last edited by Amn; April 22nd, 2003 at 07:31 AM.

  4. #4
    Join Date
    Mar 2003
    Location
    India {Mumbai};
    Posts
    3,871
    Sorry! I am not well exprienced with templates (atleast not aby better than your sound concepts)!
    My latest article: Explicating the new C++ standard (C++0x)

    Do rate the posts you find useful.

  5. #5
    Join Date
    Jun 2001
    Location
    Switzerland
    Posts
    4,443
    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.
    Code:
    callFunctor<T, pMember>(pObj); //just an example dummy really
    pMember isn't a DWORD.
    Gabriel, CodeGuru moderator

    Forever trusting who we are
    And nothing else matters
    - Metallica

    Learn about the advantages of std::vector.

  6. #6
    Join Date
    May 2001
    Location
    Oslo, Norway
    Posts
    610
    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..
    Last edited by Amn; April 22nd, 2003 at 08:45 AM.

  7. #7
    Join Date
    Jun 2001
    Location
    Switzerland
    Posts
    4,443
    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
    Gabriel, CodeGuru moderator

    Forever trusting who we are
    And nothing else matters
    - Metallica

    Learn about the advantages of std::vector.

  8. #8
    Join Date
    Sep 2002
    Posts
    1,747
    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.
    */*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/

    "It's hard to believe in something you don't understand." -- the sidhi X-files episode

    galathaea: prankster, fablist, magician, liar

  9. #9
    Join Date
    May 2001
    Location
    Oslo, Norway
    Posts
    610
    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 ?

  10. #10
    Join Date
    Sep 2002
    Posts
    1,747
    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:
    Code:
    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?
    */*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/

    "It's hard to believe in something you don't understand." -- the sidhi X-files episode

    galathaea: prankster, fablist, magician, liar

  11. #11
    Join Date
    May 2001
    Location
    Oslo, Norway
    Posts
    610
    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 !!! ;|

    Code:
    class thread
    {
    	template<class T, DWORD (T::*pMember)()> friend DWORD WINAPI functor(LPVOID pObj)
    	{
    		return (((T*)pObj)->*pMember)();
    	}
    
    	HANDLE	hThread;
    	DWORD	threadID;
    
    public:
    
    	class createThreadFailed {};
    
    	template<class T, DWORD (T::*pMember)()> thread(T* pObj)
    	{
    		hThread = CreateThread(NULL, 0, functor<T, pMember>, pObj, &threadID);
    		
    		if(!hThread) throw createThreadFailed();
    	}
    };
    Basically this is a thread class that dispatches foreign members asynchrouniously and still behold the data in its members.

  12. #12
    Join Date
    Sep 2002
    Posts
    1,747
    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:
    Code:
    template <class T>
    class functor
    {
         T* pObj_;
         DWORD (T::*pMember_)();
    public:
         functor(T* pObj, DWORD (T::*pMember)()) :
         pObj_(pObj),
         pMember_(pMember)
         { }
    
         DWORD operator()
         {
              return (pObj_->*pMember_)();
         }
    };
    
    template <class T>
    DWORD threadFunction(LPVOID threadFunctor)
    {
         return (((functor<T>*)threadFunctor)->operator());
    }
    
    class thread
    {
         HANDLE hThread;
         DWORD threadID;
    
    public:
         class createThreadFailed { };
    
         template <class T>
         thread(T* pObj, DWORD (T::*pMember)())
         {
              functor<T> *myFunctor = new functor<T>(pObj, pMember);
    
              hThread = CreateThread(NULL, 0, threadFunction<T>, myFunctor, &threadID);
    
              if (!hThread) throw createThreadFailed();
         }
    };
    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...
    */*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/

    "It's hard to believe in something you don't understand." -- the sidhi X-files episode

    galathaea: prankster, fablist, magician, liar

  13. #13
    Join Date
    Sep 2002
    Posts
    1,747
    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:
    Code:
    #include <windows.h>
    #include <iostream>
    
    using std::cout;
    
    template <class T>
    class functor
    {
         T* pObj_;
         DWORD (T::*pMember_)();
    public:
         functor(T* pObj, DWORD (T::*pMember)()) :
         pObj_(pObj),
         pMember_(pMember)
         { }
    
         DWORD operator()()
         {
              return (pObj_->*pMember_)();
         }
    };
    
    template <class T>
    DWORD WINAPI threadFunction(LPVOID threadFunctor)
    {
         return (static_cast<functor<T>*>(threadFunctor))->operator()();
    }
    
    class thread
    {
         HANDLE hThread;
         DWORD threadID;
    
    public:
         class createThreadFailed { };
    
         template <class T>
         thread(T* pObj, DWORD (T::*pMember)())
         {
              functor<T> *myFunctor = new functor<T>(pObj, pMember);
    
              hThread = CreateThread(NULL, 0, static_cast<LPTHREAD_START_ROUTINE>
                   (threadFunction<T>), myFunctor, 0, &threadID);
    
              if (!hThread) throw createThreadFailed();
         }
    };
    
    class DummyClass
    {
    public:
      DWORD DummyFunction()
      {
        cout << "Inside DummyClass::DummyFunction()!\n";
        return 0;
      }
    };
    
    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 ;).
    Last edited by galathaea; April 22nd, 2003 at 01:11 PM.
    */*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/

    "It's hard to believe in something you don't understand." -- the sidhi X-files episode

    galathaea: prankster, fablist, magician, liar

  14. #14
    Join Date
    May 2001
    Location
    Oslo, Norway
    Posts
    610

    Lightbulb 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 !

    Thanks ! See you around...

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured