Prev: templates vs inheritance.
Next: Article: On Iteration
From: Andrey Tarasevich on 18 Nov 2009 01:49 Ganesh Pagade wrote: > 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. No. This has absolutely nothing to do with the pointer 'ptr' being a member or not, i.e. there's absolutely no need to introduce a member 'ptr' into your class. The first "method" does not work simply because in C++ pointers of 'pointer-to-member' type cannot be dereferenced by '->' and '*' operators. Instead, they have to be dereferenced with '->*' and '.*' operators. Note, that '->*' and '.*' are completely independent operators, different from '->' and '*'. Pointers to members cannot be dereferenced "by themselves", since conceptually they are not really pointing into any concrete locations. Think of them as of "relative" pointers: they are relative to a concrete object. (For example, in case of pointers to _data_ members, you can think of them as _offsets_ from the beginning of the object to the actual data member.) So, in order to dereference a pointer of 'pointer-to-member' type you have to supply an additional operand: a concrete object, relative to which this pointer-to-member is supposed to be used. The object is specified on the left-hand side of '->*'/'.*' operators. This is what you did in your second method: you used '->*' operator with 'this' on the left-hand side. So, the pointer 'ptr' is used in conjunction with '*this' object. Note, again, that this has nothing to do with 'ptr' being a member of class 'Sample'. You can easily make 'ptr' a local variable for (int i = 0; i < 3; ++i) { void (Sample::*ptr)(string) = funPtrs[str[i]]; (this->*ptr)("hello"); } or you can do it without any additional variables at all for (int i = 0; i < 3; ++i) (this->*funPtrs[str[i]])("hello"); (This is how your "Method 1" should have looked from the very beginning). -- Best regards, Andrey Tarasevich [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |