Visual Studio 2012中的std::function目标方法



我有以下代码:

#include <functional>
//...
typedef int (*Myfun)(int);
std::function<int (int)> fn0([](int a)->int {
    return -a;
});
std::cout << "val == " << fn0(3) << std::endl; //"val == -3"
Myfun *fptr = fn0.target<Myfun>(); //fptr is NULL!!
std::cout << "val == " << (*fptr)(3) << std::endl; //Access violation error

实际上,这段代码是来自MSDN的代码,有一点变化:使用lambda而不是普通函数。

为什么调用fn0.target<Myfun>()返回NULL?

当我声明一个常规函数

int neg(int val) { 
    return (-val); 
}

和写std::function<int (int)> fn0(neg);,一切似乎都工作,但lambda没有正确处理。

typedef int (*Myfun)(int);中的Myfun类型与函数目标的类型无关,后者是通过执行表达式[](int a)->int { return -a; }产生的闭包对象的唯一未命名类型

试着执行std::cout << fn0.target_type().name() << 'n';自己看看。

当你用int neg(int val) { return (-val); }声明一个函数时,neg的类型恰好是Myfun(在函数到指针的转换之后,这发生在std::function<int(int)> fn0(neg)中),这就是为什么std::function::target()能够返回一个指向它的指针。

Cubbi解释了为什么你的代码不能工作——lambda不是函数指针。

现在,琐碎的lambda可以转换为函数指针。假设你真的想强迫这种转换?

template<typename F>
struct as_pointer_t {
  F f;
  template<typename R, typename... Args>
  operator type<R(*)(Args...)>() const { return {f}; }
  template<typename R, typename... Args>
  operator std::function<R(Args...)>() const { return (R(*)(Args...))f; }
};
template<typename F>
as_pointer_t<F> as_pointer( F&& f ) { return {std::forward<F>(f)}; }

现在我们可以这样做:

int main() {
  typedef int (*Myfun)(int);
  std::function<int (int)> fn0(as_pointer([](int a)->int {
    return -a;
  }));
  std::cout << "val == " << fn0(3) << std::endl; //"val == -3"
  Myfun *fptr = fn0.target<Myfun>(); //fptr is no longer NULL!!
  std::cout << "val == " << (*fptr)(3) << std::endl;
}

和您的代码按预期工作。但是,只有当lambda没有捕获到任何内容时,上面的代码才会编译。

如果您的目标是将捕获lambda转换为函数指针,则不能这样做。您可以将状态存储在全局变量中,并在非捕获lambda中使用它。您还可以将捕获lambda转换为函数指针和void*对。

我已经编写了代码,该代码使用编译时索引将void*注入到列表中(以及可选的类型来代替void*),并产生上述一对void*和函数指针。一般情况比较棘手——具体情况(比如,第一个参数)要简单得多。

template<typename T> using type=T;
template<typename F, typename X=void*>
struct callback_t {
  F f;
  operator X() { return X(&f); }
  template<typename R, typename...Args>
  operator type<R(*)(X, Args...)>() const {
    return []( X x, Args... args )->R {
      F* f = (F*)(x);
      return (*f)(std::forward<Args>(args)...);
    };
  }
};
template<typename X=void*, typename F>
callback_t<F,X> make_callback( F f ) {
  return {std::forward<F>(f)};
}

使用:

typedef void(*pfun)(void*, int);
void call_pfun( pfun f, void* p) {
  for (int i = 0; i < 3; ++i)
    f( p, i );
}
int main()
{
  int y = 7;
  auto callback = make_callback([y]( int x ) { std::cout << x+y << "n"; });
  call_pfun( callback, callback );
}

生活例子。

相关内容

最新更新