Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. Compiler Error

Compiler Error

Scheduled Pinned Locked Moved C / C++ / MFC
c++help
5 Posts 2 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • K Offline
    K Offline
    Kash
    wrote on last edited by
    #1

    Hi, I have a bit of code that works fine in non MFC C++ project. However when converting to MFC code I get the infamous C2664 compiler error. This is what I'm trying to do: double CWork::Equation(double x[]) { return (100*(x[1]-x[0]*x[0])*(x[1]-x[0]*x[0])+(1.0-x[0])*(1.0-x[0])); } double CWork::DriverFunc(double (*dblfunc)(double[]), double start[]) { min = lots of operations; return min; } void CWork::WorkIt() { double start[] = {1.,2.,3.}; double min; int i; min=DriverFunc(Equation,start); } This is the error: Work.cpp(1041) : error C2664: 'DriverFunc' : cannot convert parameter 1 from 'double (double []) const' to 'double (__cdecl *)(double [])' Any suggestions would be great. Kash

    N 1 Reply Last reply
    0
    • K Kash

      Hi, I have a bit of code that works fine in non MFC C++ project. However when converting to MFC code I get the infamous C2664 compiler error. This is what I'm trying to do: double CWork::Equation(double x[]) { return (100*(x[1]-x[0]*x[0])*(x[1]-x[0]*x[0])+(1.0-x[0])*(1.0-x[0])); } double CWork::DriverFunc(double (*dblfunc)(double[]), double start[]) { min = lots of operations; return min; } void CWork::WorkIt() { double start[] = {1.,2.,3.}; double min; int i; min=DriverFunc(Equation,start); } This is the error: Work.cpp(1041) : error C2664: 'DriverFunc' : cannot convert parameter 1 from 'double (double []) const' to 'double (__cdecl *)(double [])' Any suggestions would be great. Kash

      N Offline
      N Offline
      Nitzan Shaked
      wrote on last edited by
      #2

      Yes. You are trying to send a MEMBER FUNCTION as a "regular" (global-scope) function to CWork::DriverFunc(). You can't send pointers to member functions as "regularly" as you send pointers to "regular" functions. The discussion on this is long, and you would have no problems finding the reasons on the web. It's too long to be included here. In any case, you have three basic options: 1) If you don't care that DriverFunc() will get a CWork-method (rather than "any" function returning double and accepting a double-array), you can change it's prototype to: typedef double (*CWork::dblfunc)(double[]); double CWork::DriverFunc( dblfunc func, double start[] ) { ... } 2) Instead of passing "Equation" to DriverFunc, pass an intermediate function which will call Equation. This function will be a static member of CWork, so even if Equation() is "hidden" it will still be able to call it. This also means you'll have to pass "this". Here's how it goes: static CWork::CallEquation( CWork* That, RestOfParamsForEquation ) { That->Equation( RestOfParamsForEquation ); } and then: typedef double (*WrapperForEquation)( CWork* That, RestOfParamsForEquation ); CWork::DriverFunc( WrapperForEquation w, double start[] ) { ... ( Whever you want to call the passed function, use w(this,ParamsYouWouldLikeToPass) ) } And then in WorkIt(), call DriverFunc with CallEquation() as the first argument 3) The third option is THE ugliest by far, slightly more complex, but does EXACTLY what you want. It will only work if Equation() satisfies a list of requirements (non-virtual, non-static), is NOT portable, and like I said: ugly. But it actual usage it's the simplest, and I like it... The idea is basically to circumnavigate the compiler's type checking system (which is what yells at you in the first place), which WILL allow you get the address of CWork::Equation. You would have to use the value with care, but it can be done. I'll elaborate more if you want, but like I said: it's ugly... Good luck. -- Calius

      K 1 Reply Last reply
      0
      • N Nitzan Shaked

        Yes. You are trying to send a MEMBER FUNCTION as a "regular" (global-scope) function to CWork::DriverFunc(). You can't send pointers to member functions as "regularly" as you send pointers to "regular" functions. The discussion on this is long, and you would have no problems finding the reasons on the web. It's too long to be included here. In any case, you have three basic options: 1) If you don't care that DriverFunc() will get a CWork-method (rather than "any" function returning double and accepting a double-array), you can change it's prototype to: typedef double (*CWork::dblfunc)(double[]); double CWork::DriverFunc( dblfunc func, double start[] ) { ... } 2) Instead of passing "Equation" to DriverFunc, pass an intermediate function which will call Equation. This function will be a static member of CWork, so even if Equation() is "hidden" it will still be able to call it. This also means you'll have to pass "this". Here's how it goes: static CWork::CallEquation( CWork* That, RestOfParamsForEquation ) { That->Equation( RestOfParamsForEquation ); } and then: typedef double (*WrapperForEquation)( CWork* That, RestOfParamsForEquation ); CWork::DriverFunc( WrapperForEquation w, double start[] ) { ... ( Whever you want to call the passed function, use w(this,ParamsYouWouldLikeToPass) ) } And then in WorkIt(), call DriverFunc with CallEquation() as the first argument 3) The third option is THE ugliest by far, slightly more complex, but does EXACTLY what you want. It will only work if Equation() satisfies a list of requirements (non-virtual, non-static), is NOT portable, and like I said: ugly. But it actual usage it's the simplest, and I like it... The idea is basically to circumnavigate the compiler's type checking system (which is what yells at you in the first place), which WILL allow you get the address of CWork::Equation. You would have to use the value with care, but it can be done. I'll elaborate more if you want, but like I said: it's ugly... Good luck. -- Calius

        K Offline
        K Offline
        Kash
        wrote on last edited by
        #3

        Simple solutions have their own beauty :) In Equation(), I will eventually need to use member variables from my CWork class so I think the first method won't fit the bill. Please elaborate on the third option. Kash

        N 1 Reply Last reply
        0
        • K Kash

          Simple solutions have their own beauty :) In Equation(), I will eventually need to use member variables from my CWork class so I think the first method won't fit the bill. Please elaborate on the third option. Kash

          N Offline
          N Offline
          Nitzan Shaked
          wrote on last edited by
          #4

          All options will work for you, since all options will result with DriverFunc() being called on the correct object. The way I usually do it is option (2), actually. It's a small price to pay (1 line of code) for the generic mechanism you gain. Just in case we're not talking about the same thing when we're saying "option (2)", here's what I mean (in an all-madeup example): Let's say you have a function (or a method of some class) which needs to call some "callback" function with three parameters: an int, a double, and a char. It's customary anyways to add a "context" or "userdata" argument to such callback functions (even in plain C) so you can use the same function for several callbacks, and each of the callers will pass a different first argument ("userdata") according to what was requested when the cb func was registered. In our case we replace this "context" / "user data" with a pointer to the actual C++ instance. We define a type for the cb func: ClassMethodCbFunc -- it gets our int,double,char arguments, plus another parameter which will become the "this". ------------------------------------------------------------------------------------------- typedef int (*ClassMethodCbFunc)( void* This, int Param1, double Param2, char Param3 ); // (Note: "This" and not "this" !) ------------------------------------------------------------------------------------------- The function (or some class method) which wants to use this type looks like: ------------------------------------------------------------------------------------------- void FunctionWhichCallsMethodCb( ClassMerhodCbFunc Func, void* This ) { ... int Res = Func( This, 1, 2.0, 'c' ); ... } ------------------------------------------------------------------------------------------- ... that is: it calls it's "Func" argument with the "This" parameter it receives, and the values for Param1, Param2 and Param3 can be anything. ("Func" and "This" go together: when one is passed for a func to another, so will the other one. Just like the "CbFunc" and "userdata" in "plain" C). Now for the class which actually contains the method that will eventually be called: ------------------------------------------------------------------------------------------- class CMyClass { public: int MemthodBeingCalled( int Param1, double Param2, char Param3 ) { return Param1 + Param2 + Param3; } static int MethodBeingCalled__Wrapper( void* This, int Param1, int Param2, char Param3 ) { return

          K 1 Reply Last reply
          0
          • N Nitzan Shaked

            All options will work for you, since all options will result with DriverFunc() being called on the correct object. The way I usually do it is option (2), actually. It's a small price to pay (1 line of code) for the generic mechanism you gain. Just in case we're not talking about the same thing when we're saying "option (2)", here's what I mean (in an all-madeup example): Let's say you have a function (or a method of some class) which needs to call some "callback" function with three parameters: an int, a double, and a char. It's customary anyways to add a "context" or "userdata" argument to such callback functions (even in plain C) so you can use the same function for several callbacks, and each of the callers will pass a different first argument ("userdata") according to what was requested when the cb func was registered. In our case we replace this "context" / "user data" with a pointer to the actual C++ instance. We define a type for the cb func: ClassMethodCbFunc -- it gets our int,double,char arguments, plus another parameter which will become the "this". ------------------------------------------------------------------------------------------- typedef int (*ClassMethodCbFunc)( void* This, int Param1, double Param2, char Param3 ); // (Note: "This" and not "this" !) ------------------------------------------------------------------------------------------- The function (or some class method) which wants to use this type looks like: ------------------------------------------------------------------------------------------- void FunctionWhichCallsMethodCb( ClassMerhodCbFunc Func, void* This ) { ... int Res = Func( This, 1, 2.0, 'c' ); ... } ------------------------------------------------------------------------------------------- ... that is: it calls it's "Func" argument with the "This" parameter it receives, and the values for Param1, Param2 and Param3 can be anything. ("Func" and "This" go together: when one is passed for a func to another, so will the other one. Just like the "CbFunc" and "userdata" in "plain" C). Now for the class which actually contains the method that will eventually be called: ------------------------------------------------------------------------------------------- class CMyClass { public: int MemthodBeingCalled( int Param1, double Param2, char Param3 ) { return Param1 + Param2 + Param3; } static int MethodBeingCalled__Wrapper( void* This, int Param1, int Param2, char Param3 ) { return

            K Offline
            K Offline
            Kash
            wrote on last edited by
            #5

            Thanks for your help. I was just thinking whilst reading half way down, that you should write an article on this subject. People will definitely benefit from this. I solved the problem using ideas from your reply and now all seems to work fine. Thanks again. Kash

            1 Reply Last reply
            0
            Reply
            • Reply as topic
            Log in to reply
            • Oldest to Newest
            • Newest to Oldest
            • Most Votes


            • Login

            • Don't have an account? Register

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • World
            • Users
            • Groups