lambda调用另一个外部lambda

时间:2016-09-27 17:54:03

标签: c++ c++11 lambda

我可以很容易地做到这一点:

auto f = []()->int { return 4; };
auto g = [f]()->int { return f(); });
int i = g();

尽管如此,我不能这样做:

int (*f)() = []()->int { return 4; };
int (*g)() = [f]()->int { return f(); });
int i = g();

为什么我在MSVC中收到此消息?

error C2440: 'initializing' : cannot convert from 'ClassName::functionName::< lambda_b2eebcdf2b88a20d8b40b0a03c412089>' to 'int (__cdecl *)(void)'

这在线上发生:

int (*g)() = [f]()->int { return f(); });

如何正确地做到这一点?

2 个答案:

答案 0 :(得分:10)

int (*f)() = []()->int { return 4; };

仍然没问题,因为带有空捕获列表的lambdas会隐式转换为匹配的函数指针。

然而,第二行没有达到这个(关键)条件:

int (*g)() = [f]()->int { return f(); });
              ^

因此转换失败。

如果你想存储捕获某些内容的lambda,你需要std::function,或者像之前一样用auto推断出类型;什么适合你的用例。函数指针根本不能这样做(在C ++ 11中,对于将来,请参阅Yakk's answer)。

答案 1 :(得分:3)

好吧,你可以等待C ++ 17。

template<auto F>
struct function_ptr;
template<class R, class...Args, R(*F)(Args...)>
struct function_ptr<F> {
  using signature = R(Args...);
  constexpr R operator()(Args...args)const {
    return F(std::forward<Args>(args)...);
  }
  constexpr operator signature*() const { return F; }
  constexpr signature* operator+() const { return F; }
};

现在:

constexpr auto f_ = []()->int { return 4; };
function_ptr<+f_> f;

生成类似f的函数指针。

template<class T>struct tag_t {};

template<class F, class...Fs, class R, class...Args>
constexpr auto chain_functions(tag_t<R(Args...)>) {
  constexpr r = [](Args...args)->R{
    return F{}( Fs{}..., std::forward<Args>(args)... );
  };
  return function_ptr<+r>{};
}

让我们链接函数指针。

constexpr auto f_ = []()->int { return 4; };
function_ptr<+f_> f0;
constexpr auto g_ = [](int(*f)())->int { return f(); });
function_ptr<+g_> g_raw;
auto g0 = chain_functions< function_ptr<+g_>, function_ptr<+f_> >( tag_t<int()>{} );

现在gfunction_ptr

int(*g)() = g0;

应该有希望编译和工作。 (未经测试,我无法访问足够的C ++ 17编译器)。

还是有点迟钝,绝对没有经过测试。基本上function_ptr旨在创建一个带有编译时函数指针的类型。 C ++ 17为我们提供了constexpr lambdas,包括在constexpr上下文中从中获取函数指针的能力。

然后我们可以组合这些函数指针类型来生成一个新的函数指针类型。