8

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?

4
  • Have a look at std::bind Commented Feb 10, 2016 at 17:04
  • ^ ... and std::function when you're already at it. Commented Feb 10, 2016 at 17:05
  • 1
    Thanks. I have looked at a lot of Web pages and my head is swimming. I need some specifics. That's why I came here with this question. Commented Feb 10, 2016 at 17:07
  • Nobody managed to answer your question with mem_fn()? That's sad... Related: stackoverflow.com/questions/75551158/… Commented Feb 23, 2023 at 23:14

3 Answers 3

6

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks much! This is the level of help I need. Forgot to mention that one problem is that I have found a lot of examples of mem_fn() and bind() on the Web but none are for a function prototype and I have been unable to make that leap on my own. Can't see why I would not want to go to your std::function typedef. Not sure exactly how to specify the reference now in the call. Tried std::bind<e>(&e::setStatement) and I am getting dozens of inscrutable errors on MS templates ...
Oh, also, I am doing alpha testing in MS VS 2010 but my ultimate environment is a compiler that only offers partial C++11 support and so I cannot use lambdas.
@Charles That's not your fault, because I had a typo. Try again with revised code, please, and we'll see what else needs to be worked out.
5

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

7 Comments

Actually, will bind() return something that's convertible to a simple function pointer, as he's defined it?
@YamMarcovic - good point. valNamedFlags has to take the result of the bind expression as its final argument; in practice, that means it should either be a template or it should take std::function<void(int,bool)> where it currently takes valNamedFlagsCallback.
Thanks. Sorry to be so dense. I changed the prototype as you suggested to use std::function<void(int,bool)> callBack and I have been playing with the call -- something like std::bind(setStatement, _1, _2). I am getting literally hundreds of errors that I cannot make heads or tails of. Any more clues? Thanks much!
Oh, also tried std::bind(setStatement, this, _1, _2) and still getting hundreds of errors.
@Charles -- you should probably post either of those as a new question, including the code that's failing.
|
0

Got it!!! THANKS ALL!!!

Prototype:

bool valNamedFlags(const OptBlk *operand, const char *description_of_value_or_NULL, const int subscripts[], const char *names[], std::function<void(int,bool)> callBack);

Call:

valNamedFlags(..., std::bind(&e::setStatement, this, _1, _2));

Actually runs and calls setStatement with the proper arguments.

1 Comment

Just for completeness let me add that MS VS 2010 takes std::bind and so forth with no problem but my other compiler which is much more of a stickler for standards-conformant syntactic perfection requires std::tr1::bind() and so forth.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.