2

我想尝试一些东西并在我们的动态库 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

4

2 回答 2

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);

在这种情况下,您不再需要将返回类型作为固定参数,但现在您不会获得空值调用运算符。任你选。

于 2011-08-11T15:40:33.860 回答
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. 这可以很容易地缓解:将两者打包在一个类中,因此生命周期显然是相同的。

于 2011-08-12T10:57:36.600 回答