2016-09-27 118 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上下文中獲取函數指針的能力。

然後我們可以編寫這些函數指針類型來生成一個新的函數指針類型。