Prev: templates vs inheritance.
Next: Article: On Iteration
From: Ganesh Pagade on 17 Nov 2009 03:05 Hi, Following is isolated code reproducing the issue I encountered while using function pointers: ////////////////////////////////////////////// #include <iostream> #include <string> #include <map> using namespace std; class Sample { public: Sample() { funPtrs["fun1"] = &Sample::fun1; funPtrs["fun2"] = &Sample::fun2; funPtrs["fun3"] = &Sample::fun3; } void process() { string str[] = { "fun1", "fun2", "fun3" }; // Method 1 - Compilation error. for (int i = 0; i < 3; ++i) { // VS 2005 gives me error as: // error C2064: term does not evaluate to a function taking 1 arguments funPtrs[str[i]]("hi"); } // Method 2 - Works fine. for (int i = 0; i < 3; ++i) { ptr = funPtrs[str[i]]; (this->*ptr)("hello"); } } private: void fun1(string str) { str = "fun1"; cout << str << endl; } void fun2(string str) { str = "fun2"; cout << str << endl; } void fun3(string str) { str = "fun3"; cout << str << endl; } private: static map<string, void (Sample::*)(string)> funPtrs; void (Sample::*ptr)(string); }; map<string, void (Sample::*)(string)> Sample::funPtrs; int main() { Sample s; s.process(); return 0; } ////////////////////////////////////////////// To my understanding Method 1 gives error because function is called using pointer which is not a member of Sample, due to which "this" cannot be passed to the member function as argument. Hence the mentioned error. Adding a pointer as member variable specifically to make the function calls, works fine (Method 2). I was wondering if this is the only way to do it or there exist a better method/design to achieve this. Regards, Ganesh -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Alp Mestan on 17 Nov 2009 16:31 On Nov 17, 9:05 pm, Ganesh Pagade <ganesh.pag...(a)gmail.com> wrote: [snip] > To my understanding Method 1 gives error because function is called > using pointer which is not a member of Sample, due to which "this" > cannot be passed to the member function as argument. Hence the > mentioned error. > > Adding a pointer as member variable specifically to make the function > calls, works fine (Method 2). I was wondering if this is the only way > to do it or there exist a better method/design to achieve this. As far as I know, there isn't any more practical way. However, I write much less painfully such code using boost.bind like tools -- see [1]. Butn to sum up, when you have a member function pointer, if you want to call it on a precise instance, you have to somehow "evaluate" that adress w.r.t the given instance to be able to call it, thus the dereferencing right after 'this->'. [1] http://www.boost.org/doc/libs/1_40_0/libs/bind/bind.html#with_member_pointers -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Seungbeom Kim on 17 Nov 2009 20:48 Ganesh Pagade wrote: > > // Method 1 - Compilation error. > for (int i = 0; i < 3; ++i) > { > // VS 2005 gives me error as: > // error C2064: term does not evaluate to a function taking 1 arguments > funPtrs[str[i]]("hi"); > } > > // Method 2 - Works fine. > for (int i = 0; i < 3; ++i) > { > ptr = funPtrs[str[i]]; > (this->*ptr)("hello"); > } > > ////////////////////////////////////////////// > > To my understanding Method 1 gives error because function is called > using pointer which is not a member of Sample, due to which "this" > cannot be passed to the member function as argument. Hence the > mentioned error. > > Adding a pointer as member variable specifically to make the function > calls, works fine (Method 2). I was wondering if this is the only way > to do it or there exist a better method/design to achieve this. Is there anything bad with Method 2? I don't see any. You can, of course, skip the variable assignment and write directly: (this->*funPtrs[str[i]])("hello"); -- Seungbeom Kim [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Nick Hounsome on 17 Nov 2009 20:49 On 17 Nov, 20:05, Ganesh Pagade <ganesh.pag...(a)gmail.com> wrote: > Hi, > > Following is isolated code reproducing the issue I encountered while > using function pointers: > > ////////////////////////////////////////////// > #include <iostream> > #include <string> > #include <map> > > using namespace std; > > class Sample > { > public: > Sample() > { > funPtrs["fun1"] = &Sample::fun1; > funPtrs["fun2"] = &Sample::fun2; > funPtrs["fun3"] = &Sample::fun3; This is the wrong way to go about initialising funPtrs (appologies if this is just because you've simplified for your post). Should probably be done by the constructor of a static object of class SampleInit in Sample.cxx with the implementation of Sample() taken out of line. That way it will be done once before any Sample object is constructed. (definition of funPtrs must come before the init because the order of construction of statics in a single compilation unit is well defined) > } > > void process() > { > string str[] = { "fun1", "fun2", "fun3" }; > > // Method 1 - Compilation error. > for (int i = 0; i < 3; ++i) > { > // VS 2005 gives me error as: > // error C2064: term does not evaluate to a function taking 1 > arguments > funPtrs[str[i]]("hi"); Pointer to a member of what object???? Yes you are calling it in a member function but you could just as easily call it on another object - The compiler cannot assume that just because you are in a member of "this" that you want to call the function on "this" (see below). > } > > // Method 2 - Works fine. > for (int i = 0; i < 3; ++i) > { > ptr = funPtrs[str[i]]; > (this->*ptr)("hello"); but could just as easily be (that->*ptr)("hello"); which is why 1 doesn't work. NB there is no reason to have ptr and certainly no reason to make it a member: (this->*funPtrs[str[i]])("hello"); > } > } > > private: > void fun1(string str) > { > str = "fun1"; > cout << str << endl; > } > > void fun2(string str) > { > str = "fun2"; > cout << str << endl; > } > > void fun3(string str) > { > str = "fun3"; > cout << str << endl; > } > > private: > static map<string, void (Sample::*)(string)> funPtrs; > > void (Sample::*ptr)(string); Not needed > }; > > map<string, void (Sample::*)(string)> Sample::funPtrs; > > int main() > { > Sample s; > > s.process(); > > return 0;} > > ////////////////////////////////////////////// > > To my understanding Method 1 gives error because function is called > using pointer which is not a member of Sample, due to which "this" > cannot be passed to the member function as argument. Hence the > mentioned error. > > Adding a pointer as member variable specifically to make the function > calls, works fine (Method 2). I was wondering if this is the only way > to do it or there exist a better method/design to achieve this. See above > Regards, > Ganesh P.S. It's often helpful for this sort of mapping code to make the strings static members of the class: class Sample { ... public: static const string FUN1; That way you can maybe save a little space or time and sometimes avoid errors, at least in test programs - The strings have to be created somewhere and they have to be "known" so they might as well be in the interface. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Kwall Kuno on 18 Nov 2009 01:40
On Tue, 17 Nov 2009 14:05:42 CST, Ganesh Pagade wrote: [snip] > // VS 2005 gives me error as: > // error C2064: term does not evaluate to a function taking 1 > arguments > funPtrs[str[i]]("hi"); What's wrong with (this->*funPtrs[str[i]])("hi"); ? No extra member pointer needed. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |