Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Allowing function pointer code to work on a member function

Reply
Thread Tools

Allowing function pointer code to work on a member function

 
 
Enquiries, Hopkins Research
Guest
Posts: n/a
 
      10-22-2005


Hi all

I have a conundrum that is puzzling me.

I have a large codebase in C that I am converting to C++ as fast as possible
(i.e. slowly because I keep learning new idioms and stumbling with C++
'features'). One part of the C code is some optimisation functions that
expect a pointer to a function which is sent an array of doubles and returns
a double i.e. simplified..

void optimise( double (*funk)( double* ) );

I now have a bunch of classes with member functions which also take double*
and return double that I want to use in this optimiser, but the compiler
won't let me because:

error: argument of type 'double (namespace::class:(double*)' does not
match 'double (*)(double*)'

OK - I hadn't thought about that but felt there must be an easy answer.
However, I have tried declaring the functions in question as friends (but
the class members that the functions use are no longer available) and
sending 'pointers' to them a la BS TCPPPL p.419:

typedef double (class::*Pstd_mem)( double* pv );
Pstd_mem p = &class:pt_ll;

...but nothing I have tried so far works and I am running out of ideas. Can
any C++ gurus out there suggest a solution (that is hopefully reliable and
efficient)?

TIA and please CC replies here

Michael


_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/

_/ _/ _/_/_/ Hopkins Research Ltd
_/ _/ _/ _/
_/_/_/_/ _/_/_/ http://www.hopkins-research.com/
_/ _/ _/ _/
_/ _/ _/ _/ 'touch the future'

_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

 
Reply With Quote
 
 
 
 
Victor Bazarov
Guest
Posts: n/a
 
      10-22-2005
Enquiries, Hopkins Research wrote:
> I have a large codebase in C that I am converting to C++ as fast as
> possible (i.e. slowly because I keep learning new idioms and
> stumbling with C++ 'features'). One part of the C code is some
> optimisation functions that expect a pointer to a function which is
> sent an array of doubles and returns a double i.e. simplified..
>
> void optimise( double (*funk)( double* ) );
>
> I now have a bunch of classes with member functions which also take
> double* and return double that I want to use in this optimiser, but
> the compiler won't let me because:
>
> error: argument of type 'double (namespace::class:(double*)' does
> not match 'double (*)(double*)'


They are incompatible.

See FAQ about pointers to members. You can find the FAQ here:
http://www.parashift.com/c++-faq-lite/

> [..]


If you'll have questions after reading the FAQ, do ask them.

V


 
Reply With Quote
 
 
 
 
Jonathan Mcdougall
Guest
Posts: n/a
 
      10-22-2005
Enquiries, Hopkins Research wrote:
> Hi all
>
> I have a conundrum that is puzzling me.
>
> I have a large codebase in C that I am converting to C++ as fast as possible
> (i.e. slowly because I keep learning new idioms and stumbling with C++
> 'features'). One part of the C code is some optimisation functions that
> expect a pointer to a function which is sent an array of doubles and returns
> a double i.e. simplified..
>
> void optimise( double (*funk)( double* ) );
>
> I now have a bunch of classes with member functions which also take double*
> and return double that I want to use in this optimiser, but the compiler
> won't let me because:
>
> error: argument of type 'double (namespace::class:(double*)' does not
> match 'double (*)(double*)'
>
> OK - I hadn't thought about that but felt there must be an easy answer.
> However, I have tried declaring the functions in question as friends (but
> the class members that the functions use are no longer available) and
> sending 'pointers' to them a la BS TCPPPL p.419:
>
> typedef double (class::*Pstd_mem)( double* pv );
> Pstd_mem p = &class:pt_ll;
>
> ..but nothing I have tried so far works and I am running out of ideas. Can
> any C++ gurus out there suggest a solution (that is hopefully reliable and
> efficient)?


Free functions and member functions are different. See
http://www.parashift.com/c++-faq-lit...o-members.html,
especially 33.2. While you're there, read the whole faq, it may help
you.


Jonathan


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

 
Reply With Quote
 
Dave Rahardja
Guest
Posts: n/a
 
      10-23-2005
On Sat, 22 Oct 2005 13:48:30 -0400, "Victor Bazarov" <(E-Mail Removed)>
wrote:

>> I now have a bunch of classes with member functions which also take
>> double* and return double that I want to use in this optimiser, but
>> the compiler won't let me because:
>>
>> error: argument of type 'double (namespace::class:(double*)' does
>> not match 'double (*)(double*)'

>
>They are incompatible.


But you can use them to point to _static_ member functions, which may satisify
the OP's goal.

-dr
 
Reply With Quote
 
Ismail Pazarbasi
Guest
Posts: n/a
 
      10-23-2005
If I got it correct, you did this:

class SomeClass
{
public:

double OptimizeCallback(double*) { /* ... */ }
};

typedef double (SomeClass::*Pstd_mem)( double* pv );

// somewhere in the code
Pstd_mem p = &SomeClass::OptimizeCallback;
optimise(p);

As previous 3 posters replied, there is a distinction between a
non-member function and a member function. The distinction is that
latter one needs an additional "this" pointer (something like, "mov
ecx, this", in x86 assembly). In C++, there is no (standard and
reliable) way to know, at compile time, where the function is going to
be located.

Valentin's answers are cool. I'm not keen with libraries, and I didn't
know whether boost has such a thing. But in that case, you need to use
boost, and probably you'll need to ship boost libary (.so or .dll)
along with your binary.

There ways, arguably efficient and reliable, but they are compiler and
platform dependent. If you don't have a portability concern, I think we
can solve this problem. But again, these ways are not supported by
standard, so generated executable may not run properly, next time you
compile it with newer version of your current compiler.

What I thought, for example, is first defining an "interface", which
could be thought as a "struct of function pointers" in C, derive
classes from this interface, write a template adapter class that
returns pointer to the member function (forcibly and tricky, through
vtable offset), pass this pointer to optimise() as if it is the double
(funk*)(double*). Since standard doesn't define vtable layout, the code
won't be portable, and it may need some more tailoring, if your classes
have different inheritance model (multiple, virtual, etc). As Valentin
pointed out, this may become difficult to implement for more complex
scenarios. Again, I want to point out that I am not really sure how
safe it is! Test good and ask your compiler vendor, if you intend to
use this:

For Visual C++: (I guess it works as of VC++ 6.0)

typedef double(*PFUNK)(double*);

void optimise(PFUNK pf)
{
double d = 3.0;
pf(&d);
}


// Interface definition
struct IOptimizable
{
virtual double OptimizeCallback(double* p) = 0;
};

// your class will derive from IOptimizable interface
class SomeClass : public IOptimizable
{
public:
virtual double OptimizeCallback(double* pdbl)
{
cout << *pdbl << endl;
return *pdbl;
}
};

// adapter class, returns a pointer to the member function.
template<class T>
class OptimizeAdapter
{
const T* m_pt;
public:
explicit OptimizeAdapter(const T* pt)
:m_pt(pt)
{
}
operator PFUNK()
{
IOptimizable const* popt = static_cast<IOptimizable
const*>(m_pt);
void* pvtbl = ((void**)popt)[0]; // vtable is at offset 0
return (PFUNK)((void**)pvtbl)[0]; // one-and-the-only function
is at offset 0
}
};

int main()
{
SomeClass r;
OptimizeAdapter<SomeClass> adapt(&r);
optimise(adapt);
return 0;
}

One more point; the object of type SomeClass should live until
optimise() returns. Otherwise, all bets are off (undefined), as far as
I know.

I used an adapter class, because you may need further additions and
fine tuning before returning function pointer.

Please let me know, if you intend to use and whether it works

Ismail


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

 
Reply With Quote
 
Kai-Uwe Bux
Guest
Posts: n/a
 
      10-23-2005
Enquiries, Hopkins Research wrote:

>
>
> Hi all
>
> I have a conundrum that is puzzling me.
>
> I have a large codebase in C that I am converting to C++ as fast as
> possible (i.e. slowly because I keep learning new idioms and stumbling
> with C++
> 'features'). One part of the C code is some optimisation functions that
> expect a pointer to a function which is sent an array of doubles and
> returns a double i.e. simplified..
>
> void optimise( double (*funk)( double* ) );
>
> I now have a bunch of classes with member functions which also take
> double* and return double that I want to use in this optimiser, but the
> compiler won't let me because:
>
> error: argument of type 'double (namespace::class:(double*)' does not
> match 'double (*)(double*)'
>
> OK - I hadn't thought about that but felt there must be an easy answer.
> However, I have tried declaring the functions in question as friends (but
> the class members that the functions use are no longer available) and
> sending 'pointers' to them a la BS TCPPPL p.419:
>
> typedef double (class::*Pstd_mem)( double* pv );
> Pstd_mem p = &class:pt_ll;
>
> ..but nothing I have tried so far works and I am running out of ideas.
> Can any C++ gurus out there suggest a solution (that is hopefully reliable
> and efficient)?

[snip]

Others have already pointed out the reason for your problem. Here is a
workaround:


#include <iostream>
#include <memory>
#include <stdexcept>

template < typename T >
struct statify {

typedef T value_type;
typedef int ( T::* pmf_type ) ( int );

private:

// helper struct:
struct func_object {

value_type object;
pmf_type func;

func_object ( value_type const & o, pmf_type f )
: object ( o )
, func ( f )
{}

};

// static data:
static std::auto_ptr< func_object > fo_ptr;

// this is a monostate class:
statify ( void );
statify ( statify const & );
statify& operator= ( statify const & );
~statify ( void ) {}

public:

static
void initialize ( value_type const & t, pmf_type f )
{
fo_ptr = std::auto_ptr< func_object >( new func_object( t, f ) );
}

static
int forward ( int i ) {
if ( fo_ptr.get() == 0 ) {
throw( std::logic_error( "calling empty function object.\n" ) );
} else {
return( ((fo_ptr->object).*(fo_ptr->func))( i ) );
}
}

}; // statify

template < typename T >
std::auto_ptr< typename statify<T>::func_object > statify<T>::fo_ptr;



typedef int ( * int_to_int ) ( int );


// this is the API that uses a function pointer:
void print_exec ( int_to_int f, int i ) {
std::cout << i << " --> " << f(i) << '\n';
}


// here is our class with suitable member function:
struct xxx {

int factor;

xxx ( int f )
: factor ( f )
{}

int mult ( int i ) {
return( factor*i );
}

};

int main ( void ) {
xxx M ( 5 );
statify< xxx>::initialize ( M, &xxx::mult );
print_exec( statify<xxx>::forward, 4 );
}




Best

Kai-Uwe Bux

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

 
Reply With Quote
 
Carl Barron
Guest
Posts: n/a
 
      10-23-2005
In article <BF7F43BA.8F32%(E-Mail Removed)>, Enquiries,
Hopkins Research <(E-Mail Removed)> wrote:

> Hi all
>
> I have a conundrum that is puzzling me.
>
> I have a large codebase in C that I am converting to C++ as fast as possible
> (i.e. slowly because I keep learning new idioms and stumbling with C++
> 'features'). One part of the C code is some optimisation functions that
> expect a pointer to a function which is sent an array of doubles and returns
> a double i.e. simplified..
>
> void optimise( double (*funk)( double* ) );
>
> I now have a bunch of classes with member functions which also take double*
> and return double that I want to use in this optimiser, but the compiler
> won't let me because:
>
> error: argument of type 'double (namespace::class:(double*)' does not
> match 'double (*)(double*)'
>
> OK - I hadn't thought about that but felt there must be an easy answer.
> However, I have tried declaring the functions in question as friends (but
> the class members that the functions use are no longer available) and
> sending 'pointers' to them a la BS TCPPPL p.419:
>
> typedef double (class::*Pstd_mem)( double* pv );
> Pstd_mem p = &class:pt_ll;
>
> ..but nothing I have tried so far works and I am running out of ideas. Can
> any C++ gurus out there suggest a solution (that is hopefully reliable and
> efficient)?
>
> TIA and please CC replies here
>
> Michael
>

boost [www.boost.org] has a function wrapper that wraps function
pointers, functors, and member function calls.

boost::function<double(double)> is a class that should be a drop in
replacement for double(*)(double). It is slower than raw function
pointers but solves your problem and others.

you have optimize(double (*f)(double))

change the prototype and functioin definition to

optimize(boost::function<double(double)> f). Then it should work.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

 
Reply With Quote
 
Jonathan Mcdougall
Guest
Posts: n/a
 
      10-24-2005
Ismail Pazarbasi wrote:
> If I got it correct, you did this:
>
> class SomeClass
> {
> public:
>
> double OptimizeCallback(double*) { /* ... */ }
> };
>
> typedef double (SomeClass::*Pstd_mem)( double* pv );
>
> // somewhere in the code
> Pstd_mem p = &SomeClass::OptimizeCallback;
> optimise(p);
>
> As previous 3 posters replied, there is a distinction between a
> non-member function and a member function. The distinction is that
> latter one needs an additional "this" pointer (something like, "mov
> ecx, this", in x86 assembly).


It would be more accurate to say that you need an object to call a
member function, so you still need an object to call a member function
through a pointer.

> In C++, there is no (standard and
> reliable) way to know, at compile time, where the function is going to
> be located.


This is irrelevant and half wrong. The linker knows where in the
executable the function is located at compile time (and that's all you
need), but of course the exact location in memory is not known until
run-time.

> Valentin's answers are cool. I'm not keen with libraries, and I didn't
> know whether boost has such a thing. But in that case, you need to use
> boost, and probably you'll need to ship boost libary (.so or .dll)
> along with your binary.


Depends on what part of boost you are using. Particularily,
boost::function, boost::iterator and boost::bind only need headers.

> There ways, arguably efficient and reliable, but they are compiler and
> platform dependent. If you don't have a portability concern, I think we
> can solve this problem. But again, these ways are not supported by
> standard, so generated executable may not run properly, next time you
> compile it with newer version of your current compiler.
>
> What I thought, for example, is first defining an "interface", which
> could be thought as a "struct of function pointers" in C, derive
> classes from this interface, write a template adapter class that
> returns pointer to the member function (forcibly and tricky, through
> vtable offset), pass this pointer to optimise() as if it is the double
> (funk*)(double*). Since standard doesn't define vtable layout, the code
> won't be portable, and it may need some more tailoring, if your classes
> have different inheritance model (multiple, virtual, etc). As Valentin
> pointed out, this may become difficult to implement for more complex
> scenarios. Again, I want to point out that I am not really sure how
> safe it is! Test good and ask your compiler vendor, if you intend to
> use this:


<snip weird non-standard code>

This is illegal in C++ and is not even a behavior you can generally
count on. Please post standard and valid code only. Thounsands of
people read this newsgroup (hopefully) expecting the advices given to
be reliable.


Jonathan


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

 
Reply With Quote
 
James Dennett
Guest
Posts: n/a
 
      10-24-2005
Jonathan Mcdougall wrote:

>> Ismail Pazarbasi wrote:
>>

>
>>>>If I got it correct, you did this:
>>>>
>>>>class SomeClass
>>>>{
>>>>public:
>>>>
>>>> double OptimizeCallback(double*) { /* ... */ }
>>>>};
>>>>
>>>>typedef double (SomeClass::*Pstd_mem)( double* pv );
>>>>
>>>>// somewhere in the code
>>>>Pstd_mem p = &SomeClass::OptimizeCallback;
>>>>optimise(p);
>>>>
>>>>As previous 3 posters replied, there is a distinction between a
>>>>non-member function and a member function. The distinction is that
>>>>latter one needs an additional "this" pointer (something like, "mov
>>>>ecx, this", in x86 assembly).

>
>>
>>
>> It would be more accurate to say that you need an object to call a
>> member function, so you still need an object to call a member function
>> through a pointer.
>>
>>

>
>>>>In C++, there is no (standard and
>>>>reliable) way to know, at compile time, where the function is going to
>>>>be located.

>
>>
>>
>> This is irrelevant and half wrong. The linker knows where in the
>> executable the function is located at compile time (and that's all you
>> need), but of course the exact location in memory is not known until
>> run-time.



In the presence of virtual functions, the specific function
that would be called can vary at runtime. (It's possible
for a compiler to generate additional functions that wrap
this dispatch, in which case the linker would know, but a
different level of indirection is added.)

-- James

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

 
Reply With Quote
 
Jonathan Mcdougall
Guest
Posts: n/a
 
      10-25-2005
James Dennett wrote:
> Jonathan Mcdougall wrote:
> >> Ismail Pazarbasi wrote:
> >>>>
> >>>>In C++, there is no (standard and
> >>>>reliable) way to know, at compile time, where the function is going to
> >>>>be located.
> >>
> >> This is irrelevant and half wrong. The linker knows where in the
> >> executable the function is located at compile time (and that's all you
> >> need), but of course the exact location in memory is not known until
> >> run-time.

>
> In the presence of virtual functions, the specific function
> that would be called can vary at runtime. (It's possible
> for a compiler to generate additional functions that wrap
> this dispatch, in which case the linker would know, but a
> different level of indirection is added.)


Yes, but the location of virtual functions in the object file is still
known at compile-time. What makes them "virtual" is that a pointer
contains the address of a function and that the contained value may
change at run-time. This is only a second level of indirection.


Jonathan


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
pointer-to-member data and pointer-to-member functions and access specifiers Stephen Howe C++ 2 11-06-2012 12:32 PM
pointer to member function and pointer to constant member function Fraser Ross C++ 4 08-14-2004 06:00 PM
Function pointer member variable to non-member function Alex C++ 0 10-15-2003 05:26 PM
Function pointer member variable to non-member function slide_o_mix C++ 0 10-15-2003 03:37 PM
Passing a pointer to member function as a parameter to another member function Newsgroup - Ann C++ 5 07-30-2003 02:54 AM



Advertisments