我想尝试一下并在我们的动态库API包装器中统一一些样板代码。
基本上,我想做以下事情:
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();
}
这可能吗? (使用Boost或其他方式?)( C ++ 03 )
答案 0 :(得分:2)
我认为不能直接这样做,因为bind
创建了一个新对象,它通过引用获取函数对象和参数,并且不能重新引用引用。
但是,您可以轻松地使用可重新分配的函数指针编写自己的模板化函数包装器:
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;
};
[编辑:]请查看以下评论;保留构造函数中const引用所引用的引用可能会被危险地滥用,因此请小心,或者如果您愿意,可以按值保存a
和b
。[/]
现在您可以使用早期参数初始化仿函数:
ReAssFunctor<R, A, B> raf(a, b);
然后分配一个函数指针并调用:
raf.function = foo;
raf();
raf.function = goo;
raf();
您甚至可以通过以下方式替换呼叫运营商:
template <typename U>
U operator()(U (f*)(A, B)) const { return f(a, b); }
然后使用函数指针作为参数调用仿函数:
raf(fp1); // calls fp1(a,b);
raf(fp2); // calls fp2(a,b);
在这种情况下,您不再需要返回类型作为固定参数,但现在您没有得到一个无效的调用操作符。随便挑选。
答案 1 :(得分:1)
似乎以下可能有用:
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();
}
是的,那里有一些危险的参考资料。特别是,f
会保留对pDllFun
的引用。这可以相当容易地减轻:将两者打包在一个类中,因此生命周期明显相同。