I understand the basic problem in passing the address of a member function outside of its class. I get the feeling that mem_fn() might be the solution but I am having trouble with the specifics.
I have a member function in class p that is currently declared as
typedef void (*valNamedFlagsCallback)(const int, const bool);
bool valNamedFlags(const OptBlk *operand, const char *description_of_value_or_NULL, const int subscripts[], const char *names[], valNamedFlagsCallback callBack);
In class e I am trying to call valNamedFlags with
pInstance->valNamedFlags(operand, "Statement types", statementsSubscripts, statementsNames, std::mem_fn(&e::setStatement));
(I started out without the mem_fn() but of course that has the classic "pointers to member functions" problem. I've tried both &e::setStatement and just plain &setStatement.)
FWIW, setStatement is prototyped as
void setStatement(const int ifcid, const bool isAffirmative);
Everything works if I eliminate the mem_fn() and declare setStatement as static. I'm just pointing that out as a way of saying that I have eliminated all of the other possible issues; my only issue is the "pointers to member functions" problem. Unfortunately, setStatement() needs to be a member function, not a static.
The specific error I am getting in MS VS 2010 is
bool p::valNamedFlags(const OptBlk *,const char *,const int [],const char *[],p::valNamedFlagsCallback)' : cannot convert parameter 5 from 'std::tr1::_Mem_fn3<_Rx,_Pmf,_Arg0,_Arg1,_Arg2>' to 'p::valNamedFlagsCallback'
I would like to keep the callback declaration independent of class e; that is, I do not want to go to
typedef void (*e::valNamedFlagsCallback)(const int, const bool);
because I want to keep p more generalized than that.
Is mem_fn() the right solution or am I way off base? If so, how should I be declaring the callback in the valNamedFlags() prototype?
Or should I be pursuing a different approach?
Next Page. A member function of a class is a function that has its definition or its prototype within the class definition like any other variable. It operates on any object of the class of which it is a member, and has access to all the members of a class for that object.
Function template std::mem_fn generates wrapper objects for pointers to members, which can store, copy, and invoke a pointer to member. Both references and pointers (including smart pointers) to an object can be used when invoking a std::mem_fn.
Like variable in C, we have to declare functions before their first use in program. return_type function_name (type arg1, type arg2 .....); Declaration of a function with multiple input parameter and integer return type.
If function definition is written before main function then function declaration is not required whereas, If function definition is written after main function then we must write function declaration before main function.
Actually, you'll have a problem doing bind-like stuff as some suggested, since your callback is defined as a simple function pointer, and not a callable.
If you can afford to do it, you can change your
typedef void (*valNamedFlagsCallback)(const int, const bool);
to something like
typedef std::function<void(int, bool)> valNamedFlagsCallback
(also noting that const
on value parameters doesn't affect the signature of the function), then you can use std::bind()
,
using namespace std::placeholders;
pInstance->valNamedFlags(operand,
"Statement types",
statementsSubscripts,
statementsNames,
std::bind(&E::setStatement, e, _1, _2));
or you can use lambdas:
pInstance->valNamedFlags(operand,
"Statement types",
statementsSubscripts,
statementsNames,
[&](int i, bool b) { e->setStatement(i, b); });
If you must keep it as a simple function, then you'll have to send one which references the right object as a global/static variable.
You need to bind
an instance on it to call via a member function pointer. (i.e. std::bind(&e::setStatement, eInstance, _1, _2)
, suppose eInstance
is a pointer to an object of class e
).
using namespace std::placeholders; // for _1, _2, _3...
pInstance->valNamedFlags(operand, "Statement types", statementsSubscripts, statementsNames, std::bind(&e::setStatement, eInstance, _1, _2));
Note that the return value of std::bind
(which is unspecified) doesn't match the free function pointer type valNamedFlagsCallback
, one of the solutions is to use std::function
.
typedef std::function<void(const int, const bool)> valNamedFlagsCallback;
Simplified demo
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With