From: Ganesh Pagade on
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
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
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
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
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! ]

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