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

时间:2014-05-02 18:28:43

标签: c++ visual-studio-2012 c++11 lambda

我有以下代码:

#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没有得到正确处理。

2 个答案:

答案 0 :(得分:5)

Myfun中的typedef int (*Myfun)(int);类型与函数的目标类型无关,该函数的目标是通过执行表达式{{1}生成的闭包对象的唯一,未命名类型}}

尝试执行[](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)能够返回指针的原因。

答案 1 :(得分:1)

Cubbi解释了为什么你的代码不起作用 - lambda不是函数指针。

现在,普通的lambdas可以转换为函数指针。所以你认为你真的想强制转换?

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*),并生成{{1}对的代码和函数指针。一般情况很棘手 - 具体案例(比如第一个论点)要容易得多。

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

live example