所以我在玩GCC6及其概念實現,我認爲Haskell Prelude是一個很好的實驗來源。 Haskell的核心功能之一是函數組合,這是我需要立即解決的問題。在我知道可調用參數之前,如何約束一個懶惰的構圖?
模仿Haskell語法作爲最好的,我可以,我寫了這個功能:
template <typename F, typename G>
auto operator*(F f, G g)
{
return [f, g](auto... args) {
return f(g(args...));
}
}
偉大的工程,讓我做的東西,如:
auto add([](int a, int b) { return a + b; }
auto doubled([](int a) { return a * 2; }
auto add_then_double(doubled * add);
assert(add_then_double(2, 3) == 10);
快樂,我決定去回來並對我的函數組合應用一些約束,但由於其懶惰,我很快就遇到了問題。
首先,我寫了這個概念:
template <typename F, typename Ret, typename... Args>
concept bool Function()
{
return requires(F f, Args ...args) {
{ f(args...) } -> Ret;
}
}
其中我公司以關中Andrew Sutton's origin GitHub的項目中找到的概念。
所以我試圖申請我原來的功能。我的問題是,我不知道什麼G
返回不知道什麼參數傳遞給G
,所以我不能約束G
,我不知道什麼F
返回時不知道它給出了什麼參數,我不知道,因爲我不知道什麼G
返回。
我很確定我需要一個不關心返回類型的新的Function
概念,因爲我的組合函數並不在乎F
返回什麼,只要它是可調用的。我想我可以把約束放在內部lambda上,參數類型和正確的G,因此對於F,但這意味着我可以編寫非可組合函數,直到調用站點不會出錯。這是可以避免的嗎?
也許是這樣的:
template <typename F, typename G>
auto operator*(F f, G g)
{
return [f, g](auto... args)
// is it even possible to constrain here?
requires FunctionAnyReturn<G, decltype(args)...>
&& FunctionAnyReturn<F, decltype(G(decltype(args)...))>
{
return f(g(args...));
}
}
這是我能做的最好的(如果我甚至可以做到這一點)?
感謝啊,這看起來像解決方案。這是一個恥辱,因爲我不喜歡這樣一個事實,即我可以在沒有概念錯誤的情況下編寫兩個不可調用的對象。無論如何,我可以提供一個不需要參數類型的回調的Callable變體嗎? –
@ SamKellett不開箱即用。你可以選擇遵守一個協議,在這個協議中,函數對象必須使它們的'簽名'或其他東西接近它,但這是一個巨大的任務,沒有明顯的好處。 –
公平,謝謝你的回答 –