Reputation: 38785
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
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
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