From: Andrey Tarasevich on
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! ]

First  |  Prev  | 
Pages: 1 2
Prev: templates vs inheritance.
Next: Article: On Iteration