2016-09-27 96 views
3

我可以很容易地做到这一点:拉姆达调用另一个外部拉姆达

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

如果这是在命名空间范围,你可以忽略捕获列表中的'f'。 –

回答

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

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

这(关键)条件被然而未在第二线满足:

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

因此转换失败。

如果要存储捕获某物的lambda,则需要使用std::function,或者按照之前的方法使用auto来推断类型;无论适合你的用例。函数指针根本无法做到这点(在C++ 11中,未来,请参阅Yakk's answer)。

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

now gfunction_ptr

int(*g)() = g0; 

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

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

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