【问题标题】:Binding the parameters before setting the function pointer?在设置函数指针之前绑定参数?
【发布时间】:2011-08-11 15:27:16
【问题描述】:

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

【问题讨论】:

  • 我担心不可能......但让我们等待真正的答案:)

标签: c++ bind function-pointers boost-bind function-object


【解决方案1】:

我不认为可以这样直接完成,因为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;
};

[编辑:] 请检查下面的 cmets;在构造函数中保存由 const 引用获取的引用可能会被危险地滥用,所以要小心,或者如果您愿意,可以按值保存 ab。[/]

现在您可以使用参数及早初始化仿函数:

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

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

【讨论】:

  • 感谢您的示例。不幸的是,我有大约 50 个不同的函数可以这样调用,所以我必须为所有的 arities 提供不同的模板。
  • 注意:你应该never, ever initialize a member reference from a const-ref parameter! (如果我要实现这个,我会看看 boost::function 并按值保留 ab 成员。
  • @Martin:有趣的一点。持有引用不会延长临时的生命周期吗?不过,我不确定替代方案是否更好:复制需要可复制的参数并且可能很昂贵,并且指针(如链接帖子中所建议的)以一种尴尬的方式改变了界面。最好的办法是使用 C++0x 并删除一个已删除的右值引用重载!
  • 不,只有在同一本地范围内的临时对象才能延长生命周期。至于复制:Boost.Bind 还有internally copies its arguments,如果需要实际参考,他们建议使用boost::[c]ref。至于指针:是的,它们会很尴尬。
  • @Martin:我明白了——复制并选择性地使用ref(现在也是std::ref!)似乎是一种更安全的方法。我会在答案中添加评论。
【解决方案2】:

似乎以下方法可能有效:

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 的引用。这可以很容易地缓解:将两者打包在一个类中,因此生命周期显然是相同的。

【讨论】:

    猜你喜欢
    • 2014-07-30
    • 1970-01-01
    • 2017-05-29
    • 2013-10-18
    • 1970-01-01
    • 1970-01-01
    • 2021-09-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多