Martin Ba
Martin Ba

Reputation: 38785

Binding the parameters before setting the function pointer?

I would like to try something out and unify some boilerplate code in one of our dynamic library API wrappers.

Essentially, I would like to do the following:

typedef bool (*MyFPtrT)(long id, std::string const& name);
typedef boost::function<bool (long id, std::string const& name)> MyFObjT;
...

...
  MyFPtrT pDllFun = NULL;
  long x = 42; string s = "Answer"; // API input, not hardcoded
  MyFObjT f = boost::bind(pDllFun, x, s);
  ...
  return Call(f);
...

template<FT>
bool Call(FT f) {
  ...
  MyFPtrT pDllFun = (MyFunPtr)::GetProcAddress(...);
  f.setFunctionPointerButLeaveBoundParameters(pDllFun); // <- how??
  // Now call the correctly rigged up function object:
  return f();
}

Is this possible? (With Boost or otherwise?) (C++03)

Upvotes: 2

Views: 881

Answers (2)

MSalters
MSalters

Reputation: 179897

Seems the following might work:

typedef bool (*MyFPtrT)(long id, std::string const& name);
typedef boost::function<bool (long id, std::string const& name)> MyFObjT;
...

...
  MyFPtrT pDllFun = NULL;
  long x = 42; string s = "Answer"; // API input, not hardcoded
  MyFObjT f = boost::bind(boost::ref(pDllFun), x, s);
  ...
  return Call(f, pDllFun);
...

template<class FT, class FP>
bool Call(FT f, FP& pDllFun) {
  pDllFun = (MyFunPtr)::GetProcAddress(...);
  return f();
}

Yeah, there are some dangerous references around there. In particular, f keeps a reference to pDllFun. This can be mitigated fairly easy: pack the two in a single class, so the lifetimes are obviously identical.

Upvotes: 1

Kerrek SB
Kerrek SB

Reputation: 477090

I don't think it can be done directly like that, because bind creates a new object that takes the function object and the arguments by reference, and you can't rebind references.

However, you can easily enough write your own templated functor wrapper with a reassignable function pointer:

template <typename R, typename A, typename B>
struct ReAssFunctor
{
  typedef R(*FP)(A, B);

  ReAssFunctor(const A & a_, const B & b_) a(a_), b(b_) { }

  R operator()() const { return func(a, b); }

  FP function;

private:
  const A & a;
  const B & b;
};

[Edit:] Do check the comments below; holding references taken by const reference in the constructor can be dangerously abused, so be careful, or save a and b by value if you prefer.[/]

Now you can initialize the functor with the arguments early:

ReAssFunctor<R, A, B> raf(a, b);

Then assign a function pointer and call:

raf.function = foo;
raf();

raf.function = goo;
raf();

You could even replace the call operator by this:

  template <typename U>
  U operator()(U (f*)(A, B)) const { return f(a, b); }

And then invoke the functor with the function pointer as the argument:

raf(fp1);  // calls fp1(a,b);
raf(fp2);  // calls fp2(a,b);

In that case you don't need the return type as a fixed parameter any longer, but now you don't get a nullary call operator. Take your pick.

Upvotes: 2

Related Questions