我可以很容易地做到这一点:
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(); });
如何正确地做到这一点?
答案 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()>{} );
现在g
是function_ptr
。
int(*g)() = g0;
应该有希望编译和工作。 (未经测试,我无法访问足够的C ++ 17编译器)。
还是有点迟钝,绝对没有经过测试。基本上function_ptr
旨在创建一个带有编译时函数指针的类型。 C ++ 17为我们提供了constexpr
lambdas,包括在constexpr
上下文中从中获取函数指针的能力。
然后我们可以组合这些函数指针类型来生成一个新的函数指针类型。