You are on page 1of 7

convert std::bind to function pointer

Asked 11 years, 5 months ago Modified 11 years, 5 months ago Viewed 44k times

I have a third-party library which has a method that takes a function pointer as the first parameter:

49 int third_party_method(void (*func)(double*, double*, int, int, double*), ...);

I want to pass a pointer to a class' method that is declared as follows:

class TestClass
{
public:
void myFunction (double*, double*, int, int, void*);

I tried to pass this function as follows:

TestClass* tc = new TestClass();


using namespace std::placeholders;
third_party_method(std::bind(&TestClass::myFunction, tc, _1, _2, _3, _4, _5),
...);

However, this does not compile:

Conversion of parameter 1 from 'std::tr1::_Bind<_Result_type,_Ret,_BindN>' to


'void (__cdecl *)(double *,double *,int,int,void *)' is not possible
with
[
_Result_type=void,
_Ret=void,
_BindN=std::tr1::_Bind6<std::tr1::_Callable_pmf<void (__thiscall
TestClass::* const )(double *,double *,int,int,void
*),TestClass,false>,TestClass
*,std::tr1::_Ph<1>,std::tr1::_Ph<2>,std::tr1::_Ph<3>,std::tr1::_Ph<4>,std::tr1::_P
]

Is there any way I can pass the member to the function?

c++ function-pointers

Share Improve this question Follow asked Nov 5, 2012 at 18:24


Nico Schertler
32.3k 4 42 72

1 No. You need to write a function with the needed signature. You cannot get a pointer to one from a function object.
– n. m. could be an AI Nov 5, 2012 at 18:31

Not possible - see this question. – didierc Nov 5, 2012 at 18:41

If your third party library requires that you supply callbacks without the facility to supply an opaque context
parameter of some kind, you're basically doomed. If access to that library is singlethreaded, or multithreaded by the
object instance holding the callback function never changes during runtime, you can make use of a normal function
and a static pointer to a class instance. Blame the third party; if you've paid them money you may be able to hassle
them about this. – Rook Nov 5, 2012 at 18:53

1 To other people coming to C++ from C: don't define your callbacks as function pointers, use functors instead. Look
up std::function . Then you'll be able to bind the this pointer to a method, and pass it as a "function pointer"
(functor). – plafer Jan 29, 2021 at 19:06

4 Answers Sorted by: Highest score (default)

Is there any way I can pass the member to the function?

21
Unless your class object is some kind of global object - it is not possible. Because objects may contain
some data, while function pointer is just pointer to function - it doesn't contain any runtime context, only
compile-time one.

If you accept having compile-time unique IDs for each callback passing, then you can use following
generalized approach.

Usage:

void test(void (*fptr)())


{
fptr();
}

struct SomeStruct
{
int data;
void some_method()
{
cout << data << endl;
}
void another_method()
{
cout << -data << endl;
}
};

int main()
{
SomeStruct local[] = { {11}, {22}, {33} };

test(get_wrapper<0>( boost::bind(&SomeStruct::some_method,local[0]) ));


test(get_wrapper<1>( boost::bind(&SomeStruct::another_method,local[0]) ));

test(get_wrapper<2>( boost::bind(&SomeStruct::some_method,local[1]) ));


test(get_wrapper<3>( boost::bind(&SomeStruct::another_method,local[1]) ));

test(get_wrapper<4>( boost::bind(&SomeStruct::some_method,local[2]) ));


test(get_wrapper<5>( boost::bind(&SomeStruct::another_method,local[2]) ));
}

It may not require Unique ID's for each invocation, for instance because Functors may already have
different types, or runtime scope of their usage do not overlap. But it is safer to use unique ID each time.

Implementation:

live demo
#include <boost/optional.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <ostream>
using namespace std;

template<unsigned ID,typename Functor>


boost::optional<Functor> &get_local()
{
static boost::optional<Functor> local;
return local;
}

template<unsigned ID,typename Functor>


typename Functor::result_type wrapper()
{
return get_local<ID,Functor>().get()();
}

template<typename ReturnType>
struct Func
{
typedef ReturnType (*type)();
};

template<unsigned ID,typename Functor>


typename Func<typename Functor::result_type>::type get_wrapper(Functor f)
{
(get_local<ID,Functor>()) = f;
return wrapper<ID,Functor>;
}

// ----------------------------------------------------------------------

void test(void (*fptr)())


{
fptr();
}

struct SomeStruct
{
int data;
void some_method()
{
cout << data << endl;
}
void another_method()
{
cout << -data << endl;
}
};

int main()
{
SomeStruct local[] = { {11}, {22}, {33} };

test(get_wrapper<0>( boost::bind(&SomeStruct::some_method,local[0]) ));


test(get_wrapper<1>( boost::bind(&SomeStruct::another_method,local[0]) ));

test(get_wrapper<2>( boost::bind(&SomeStruct::some_method,local[1]) ));


test(get_wrapper<3>( boost::bind(&SomeStruct::another_method,local[1]) ));

test(get_wrapper<4>( boost::bind(&SomeStruct::some_method,local[2]) ));


test(get_wrapper<5>( boost::bind(&SomeStruct::another_method,local[2]) ));
}

P.S. Beaware of multi-thread access - in such cases you should use some kind of Thread-local storage
data.
Share Improve this answer Follow edited Nov 5, 2012 at 20:16 answered Nov 5, 2012 at 18:29
Evgeny Panasyuk
9,144 1 35 56

Thanks. I will consider this approach. – Nico Schertler Nov 5, 2012 at 18:53

1 Superb. I was thinking about something similar, but now there's your solution! – Dmitry Ledentsov Nov 6, 2012 at
10:05

here's a version with the unique_ids based on BOOST_PP_COUNTER – Dmitry Ledentsov Nov 6, 2012 at 10:42

1 @DmitryLedentsov, I thought about it. But, note - different translation units may have same counters numbers - so I
prefer to use explicit ID's. Just for your intereset - there are implementations of compile time counters based on
compiler-dependend bugs, without macros: rsdn.ru/forum/cpp/2337951.flat – Evgeny Panasyuk Nov 6, 2012 at
13:21

As other people mentioned you have no choice but to use global or static data to provide bind call
context as raw function. But provided solution is not general, it's stuck with empty parameter list of
7 functor. You will need to write manually wrapper , get_wrapper and Func for each different function
signature you want to bind and give them different names.

I would like to propose more generalized solution for raw bind:

#include <iostream>
#include <memory>
#include <functional>
#include <cassert>

// Raw Bind - simulating auto storage behavior for static storage data
template <typename BindFunctor, typename FuncWrapper> class scoped_raw_bind
{
public:

typedef scoped_raw_bind<BindFunctor, FuncWrapper> this_type;

// Make it Move-Constructible only


scoped_raw_bind(const this_type&) = delete;
this_type& operator=(const this_type&) = delete;
this_type& operator=(this_type&& rhs) = delete;

scoped_raw_bind(this_type&& rhs): m_owning(rhs.m_owning)


{
rhs.m_owning = false;
}

scoped_raw_bind(BindFunctor b): m_owning(false)


{
// Precondition - check that we don't override static data for another
raw bind instance
if(get_bind_ptr() != nullptr)
{
assert(false);
return;
}
// Smart pointer is required because bind expression is copy-
constructible but not copy-assignable
get_bind_ptr().reset(new BindFunctor(b));
m_owning = true;
}

~scoped_raw_bind()
{
if(m_owning)
{
assert(get_bind_ptr() != nullptr);
get_bind_ptr().reset();
}
}

decltype(&FuncWrapper::call) get_raw_ptr()
{
return &FuncWrapper::call;
}

static BindFunctor& get_bind()


{
return *get_bind_ptr();
}

private:

bool m_owning;

static std::unique_ptr<BindFunctor>& get_bind_ptr()


{
static std::unique_ptr<BindFunctor> s_funcPtr;
return s_funcPtr;
}

};

// Handy macro for creating raw bind object


// W is target function wrapper, B is source bind expression
#define RAW_BIND(W,B) std::move(scoped_raw_bind<decltype(B), W<decltype(B),
__COUNTER__>>(B));

// Usage
///////////////////////////////////////////////////////////////////////////

// Target raw function signature


typedef void (*TargetFuncPtr)(double, int, const char*);

// Function that need to be called via bind


void f(double d, int i, const char* s1, const char* s2)
{
std::cout << "f(" << d << ", " << i << ", " << s1 << ", " << s2 << ")" <<
std::endl;
}

// Wrapper for bound function


// id is required to generate unique type with static data for
// each raw bind instantiation.
// THE ONLY THING THAT YOU NEED TO WRITE MANUALLY!
template <typename BindFunc, int id = 0> struct fWrapper
{
static void call(double d, int i, const char* s)
{
scoped_raw_bind<BindFunc, fWrapper<BindFunc, id>>::get_bind()(d, i, s);
}
};

int main()
{
using namespace std::placeholders;

auto rf1 = RAW_BIND(fWrapper, std::bind(&f, _1, _2, _3, "This is f trail -


1"));
TargetFuncPtr f1 = rf1.get_raw_ptr();
f1(1.2345, 42, "f1: Bind! Bind!");

auto rf2 = RAW_BIND(fWrapper, std::bind(&f, _1, _2, _3, "This is f trail -


2"));
TargetFuncPtr f2 = rf2.get_raw_ptr();
f2(10.2345, 420, "f2: Bind! Bind!");

auto rf3 = RAW_BIND(fWrapper, std::bind(&f, _1, _2, _3, "This is f trail -


3"));
TargetFuncPtr f3 = rf3.get_raw_ptr();
f3(100.2345, 4200, "f3: Bind! Bind!");
}

It was tested - see Live Action Here

Share Improve this answer Follow answered Nov 7, 2012 at 22:44


Rost
8,889 28 52

It doesn't compile because the third-party function is expecting a pointer-to-function, but you are trying to
pass it a pointer-to-member-function. The two types are fundamentally different, and cannot be
6 interchanged. In fact, pointers-to-member-functions are very often strange animals.

Here's an SSCCE illustrating the problem you're having:

#include <iostream>
#include <iomanip>
using namespace std;

typedef void(*SpeakFn)(void);

void Bark()
{
cout << "WOOF" << endl;
}

void Meow()
{
cout << "meeow" << endl;
}

void SpeakUsing(SpeakFn fn)


{
fn();
}

class Alligator
{
public:
void Speak()
{
cout << "YAWWW" << endl;
}
typedef void(Alligator::*AlligatorSpeakFn)(void);

void SpeakUsing(AlligatorSpeakFn fn)


{
(this->*fn)();
}
};

int main()
{
SpeakUsing(&Bark); // OK

Alligator a;
Alligator::AlligatorSpeakFn mem_fn = &Alligator::Speak;
a.SpeakUsing(mem_fn); // OK

SpeakUsing(mem_fn); // NOT OK -- can't cvt from fn-ptr to mem-fn-ptr


}

You can't call SpeakUsing with a pointer-to-member-function because it's not convertible to pointer-to-
function.
Use a static member function instead, such as:

class Alligator
{
public:
static void Speak()
{
cout << "YAWWW" << endl;
}
typedef void(*AlligatorSpeakFn)(void);

void SpeakUsing(AlligatorSpeakFn fn)


{
fn();
}
};

Share Improve this answer Follow answered Nov 5, 2012 at 18:51


John Dibling
101k 32 188 325

No, not easily. The problem is that a function pointer has one chunk of info - the address of the function.
A method needs both that and the address of the object, or alternatively it could be passed the objects
1 address as a parameter.

There are extremely hackey ways to do this, but they are going to be platform specific. And extremely
hackey. So much so that I will recommend global variables instead of using them.

You do know how to do this if there is a single global instance of the class, right?

Share Improve this answer Follow answered Nov 5, 2012 at 18:32


Yakk - Adam
Nevraumont
268k 29 339 539

Yes, I do know that. Although global variables and functions do not fit nicely into our architecture. – Nico Schertler
Nov 5, 2012 at 18:34

You might also like