所以我在玩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不开箱即用。你可以选择遵守一个协议,在这个协议中,函数对象必须使它们的'签名'或其他东西接近它,但这是一个巨大的任务,没有明显的好处。 –
公平,谢谢你的回答 –