Topic: passing member function as a parameter
Author: Bala Swaminathan <bala.swaminathan@fnc.fujitsu-ABC.com>
Date: Fri, 27 Apr 2001 03:32:43 GMT Raw View
(Please remove "-ABC" in my email before replying to me)
I tried to pass a member function as an argument to a function and
Solaris CC is complaining. However, g++ -Wall compiles with no warnings:
// FILE v.cc
//
#include <iostream.h>
class Base {
public:
virtual void foo()=0;
void foobar() { cout << "Base::foobar()" << endl; }
};
class A : public Base {
public:
virtual void foo() { cout << "A::foo()" << endl; }
};
class B : public A {
public:
virtual void foo() { cout << "B::foo()" << endl; }
};
A theA;
B theB;
typedef void (*Fvv)();
void foo(Fvv f) { f(); }
main()
{
Base* ba = &theA;
foo( (Fvv) (ba->foobar)); // line 27
foo( (Fvv) (ba->foo)); // line 28
foo( (Fvv) (theB.foo)); // line 29
}
Here are the compiled outputs. Can anyone please tell me what the
standard says about this? I added a typedef for "void (Base::*BFvv)()"
and then, tried foo ( (Fvv) (BFvv) (ba->foo)), and got the same
results. Please also point me to where I can find information
corresponding to this in the standards.
$g++ -Wall v.cc
$a.out
Base::foobar()
A::foo()
B::foo()
$g++ -v
gcc -v
Reading specs from /pub/lib/gcc-lib/sparc-sun-solaris2.4/2.7.2.1/specs
gcc version 2.7.2.1
$CC v.cc
"v.cc", line 27: Error: Taking address of the bound function Base::foobar().
"v.cc", line 28: Error: Taking address of the bound function Base::foo().
"v.cc", line 29: Error: Taking address of the bound function B::foo().
3 Error(s) detected.
$CC -v
### CC: Note: LM_LICENSE_FILE = 7159@soyuz:7159@curly:7159@larry
### CC: Note: NLSPATH = /apps/sparcworks/v5.1/solaris/SUNWspro/bin/../SC4.2/bin/../lib/locale/%L/LC_MESSAGES/%N.cat:/apps/sparcworks/v5.1/solaris/SUNWspro/bin/../SC4.2/bin/../../lib/locale/%L/LC_MESSAGES/%N.cat
Thanks much
Bala
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Anthony Williams" <anthwil@nortelnetworks.com>
Date: Fri, 27 Apr 2001 17:25:01 GMT Raw View
"Bala Swaminathan" <bala.swaminathan@fnc.fujitsu-ABC.com> wrote in message
news:qjy7l07hws6.fsf@tdd1006.i-have-a-misconfigured-system-so-shoot-me...
>
> (Please remove "-ABC" in my email before replying to me)
>
> I tried to pass a member function as an argument to a function and
> Solaris CC is complaining. However, g++ -Wall compiles with no warnings:
>
> // FILE v.cc
> //
> #include <iostream.h>
> class Base {
> public:
> virtual void foo()=0;
> void foobar() { cout << "Base::foobar()" << endl; }
> };
> class A : public Base {
> public:
> virtual void foo() { cout << "A::foo()" << endl; }
> };
> class B : public A {
> public:
> virtual void foo() { cout << "B::foo()" << endl; }
> };
> A theA;
> B theB;
>
> typedef void (*Fvv)();
>
> void foo(Fvv f) { f(); }
>
> main()
> {
> Base* ba = &theA;
> foo( (Fvv) (ba->foobar)); // line 27
> foo( (Fvv) (ba->foo)); // line 28
> foo( (Fvv) (theB.foo)); // line 29
> }
>
> Here are the compiled outputs. Can anyone please tell me what the
> standard says about this? I added a typedef for "void (Base::*BFvv)()"
> and then, tried foo ( (Fvv) (BFvv) (ba->foo)), and got the same
> results. Please also point me to where I can find information
> corresponding to this in the standards.
[sample output snipped]
g++ is wrong, and Sun CC is right - this is not permitted (5.2.5p4 of the
standard), regarding E1.E2
"Otherwise, if E1.E2 refers to a non-static member function, and the type of
E2 is "function of (parameter type list) cv returning T", then E1.E2 is not
an lvalue. The expression designates a non-static member function. The
expression can be used only as the left-hand operand of a member function
call (9.3). The type of E1.E2 is "function of (parameter type list) cv
returning T".
This is a non-standard extension which obviously g++ implements, and Borland
C++ implements as well (though they call it a "closure"). I am surprised
that assignment to a plain function pointer works (even allowing the support
for "closures"), since the compiler has to store the "this" pointer to pass
to the member function, as well as the member function pointer, which I
would expect to require more memory than just a function pointer.
Anthony
--
Anthony Williams
Software Engineer, Nortel Networks Optoelectronics
The opinions expressed in this message are not necessarily those of my
employer
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: Ron Natalie <ron@spamcop.net>
Date: Fri, 27 Apr 2001 17:25:26 GMT Raw View
>
> I tried to pass a member function as an argument to a function and
> Solaris CC is complaining. However, g++ -Wall compiles with no warnings:
Your program isn't compliant. I don't know what the sun compiler thinks
it's doing.
You can't assign the address of a non-static member function to a regular
pointer-to-function. They're not compatible. How is it supposed to know
what object the member is called on? (All objects of a given class share
the same member function).
You could use pointer to member, but the syntax is different (and you still
need to provide an object pointer to call it on). But also, you run into
problems in that there is no differentiation between the base and virtual
members when you do this. Just what exactly are you trying to accomplish.
(The compiler should have also griped about the missing "int" return on main).
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: Ole Reinartz <ole.reinartz@gmx.de>
Date: Fri, 27 Apr 2001 17:25:10 GMT Raw View
Bala Swaminathan wrote:
> (Please remove "-ABC" in my email before replying to me)
>
> I tried to pass a member function as an argument to a function and
> Solaris CC is complaining. However, g++ -Wall compiles with no warnings:
maybe the reason for g++ not complaining is the age of the version you use...
>
>
> // FILE v.cc
> //
> #include <iostream.h>
> class Base {
> public:
> virtual void foo()=0;
> void foobar() { cout << "Base::foobar()" << endl; }
> };
> class A : public Base {
> public:
> virtual void foo() { cout << "A::foo()" << endl; }
> };
> class B : public A {
> public:
> virtual void foo() { cout << "B::foo()" << endl; }
> };
> A theA;
> B theB;
>
> typedef void (*Fvv)();
below you pass member functions to foo(), so you should adapt your typedef accordingly:
typedef void (Base::*Fvv)();
>
>
> void foo(Fvv f) { f(); }
because you are calling member functions you should also pass the object you want to call that on:
void foo(Base* b,Fvv f) { (b->*f)(); }
>
>
> main()
> {
> Base* ba = &theA;
> foo( (Fvv) (ba->foobar)); // line 27
> foo( (Fvv) (ba->foo)); // line 28
> foo( (Fvv) (theB.foo)); // line 29
> }
For member functions (more specifc for pointers to members) you have to explicitly say you want to pass the _address_ :
main()
{
Base* ba = &theA;
foo( ba, (Fvv) &(ba->foobar)); // line 27
foo( ba, (Fvv) &(ba->foo)); // line 28
foo( &theB, (Fvv) &(theB.foo)); // line 29
}
But still my gcc (2.95) doesnt eat it (gcc- problem as it seems).
One solution is this: which member functions belong to which object is a static thing, i.e. a property of the class. So if you specifiy which member function to call, you can do that also by specifying the class
the method belongs to:
main()
{
Base* ba = &theA;
foo( ba, (Fvv) &(Base::foobar)); // line 27
foo( ba, (Fvv) &(Base::foo)); // line 28
foo( &theB, (Fvv) &(Base::foo)); // line 29
}
This is what I normally do. Note that, because a 'pointer to member' is not a normal pointer, even if you specify Base::foo to be called in line 29, actually B::foo gets called, becasue you pass it a pointer which
points to a B.
hope this helps...
Ole
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: Ron Natalie <ron@spamcop.net>
Date: Fri, 27 Apr 2001 18:39:55 GMT Raw View
Ole Reinartz wrote:
>
> Base* ba = &theA;
> foo( ba, (Fvv) &(Base::foobar)); // line 27
> foo( ba, (Fvv) &(Base::foo)); // line 28
> foo( &theB, (Fvv) &(Base::foo)); // line 29
> }
GACK. The fact that a cast is necessary here is a big tipoff. There's
no guarantee that this works. Pointer to derived member is not necessarily
convertable to pointer to base member.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: Michiel Salters<Michiel.Salters@cmg.nl>
Date: Fri, 27 Apr 2001 23:05:14 GMT Raw View
In article <qjy7l07hws6.fsf@tdd1006.i-have-a-misconfigured-system-so-shoot-me>,
Bala Swaminathan says...
>
>
>(Please remove "-ABC" in my email before replying to me)
>
>I tried to pass a member function as an argument to a function and
>Solaris CC is complaining. However, g++ -Wall compiles with no warnings:
>
>// FILE v.cc
>//
>#include <iostream.h>
>class Base {
>public:
> virtual void foo()=0;
> void foobar() { cout << "Base::foobar()" << endl; }
>};
>class A : public Base {
>public:
> virtual void foo() { cout << "A::foo()" << endl; }
>};
>class B : public A {
>public:
> virtual void foo() { cout << "B::foo()" << endl; }
>};
>A theA;
>B theB;
>
>typedef void (*Fvv)();
Warning: Fvv is NOT a pointer to a member function; it is a pointer
to a free function.
>void foo(Fvv f) { f(); }
Therefore foo is a function taking a pointer to a free function taking
no arguments.
int // no implicit int in C++
>main() {
> Base* ba = &theA;
> foo( (Fvv) (ba->foobar)); // line 27
> foo( (Fvv) (ba->foo)); // line 28
> foo( (Fvv) (theB.foo)); // line 29
>}
Neither of the functions is a free function; all names
refer to member functions.
>Here are the compiled outputs. Can anyone please tell me what the
>standard says about this? I added a typedef for "void (Base::*BFvv)()"
>and then, tried foo ( (Fvv) (BFvv) (ba->foo)), and got the same
>results. Please also point me to where I can find information
>corresponding to this in the standards.
>$g++ -Wall v.cc
>$a.out
>Base::foobar()
>A::foo()
>B::foo()
>$g++ -v
>Reading specs from /pub/lib/gcc-lib/sparc-sun-solaris2.4/2.7.2.1/specs
>gcc version 2.7.2.1
That is a very old g++. You should consider 2.95.2 or 2.95.3, they're
much closer to the standard.
>$CC v.cc
>"v.cc", line 27: Error: Taking address of the bound function Base::foobar().
>"v.cc", line 28: Error: Taking address of the bound function Base::foo().
>"v.cc", line 29: Error: Taking address of the bound function B::foo().
>3 Error(s) detected.
Well, that is helpful. You can't take their address as if they're free
functions.
>Thanks much
>Bala
This of course does not answer the question of how to do what you want.
That is not a simple answer to give. Taking the address of a member is
not to hard: &Base::foobar gives you such a pointer. But that is a
pointer to a member. As with all member accesses, you need an object with
it too. If you have an A object the_A, the_A.*(mem_ptr)() will call the
designated member function (8.3.3, Pointers to members).
HTH,
--
Michiel Salters
Consultant Technical Software Engineering
CMG Trade, Transport & Industry
Michiel.Salters@cmg.nl
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]