Also spiele ich mit GCC6 und dessen Konzeptimplementierung und ich dachte, das Haskell Prelude wäre eine gute Quelle für Experimente. Eines der Kernmerkmale von Haskell ist die Funktionszusammensetzung, und das musste ich sofort angehen.Wie beschränke ich eine faule Komposition, bevor ich die aufrufbaren Argumente kenne?
Imitieren die Haskell Syntax wie am besten, dass ich konnte, ich diese Funktion schrieb:
template <typename F, typename G>
auto operator*(F f, G g)
{
return [f, g](auto... args) {
return f(g(args...));
}
}
die großen Werke und ermöglicht es mir, Dinge zu tun wie:
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);
Glücklich, habe ich beschlossen, gehen Zurück und wenden Sie einige Einschränkungen für meine Funktion Zusammensetzung, aber ich habe schnell ein Problem aufgrund seiner Faulheit.
Zuerst schrieb ich dieses Konzept:
template <typename F, typename Ret, typename... Args>
concept bool Function()
{
return requires(F f, Args ...args) {
{ f(args...) } -> Ret;
}
}
Was ich der gefundenen Begriffe in Andrew Sutton's origin Github-Projekt basiert.
Und so habe ich versucht, auf meine ursprüngliche Funktion anzuwenden. Das Problem, das ich habe, ist, dass ich nicht weiß, was G
zurückkehrt, ohne zu wissen, welche Argumente an G
übergeben werden, so kann ich G
nicht beschränken und ich weiß nicht, was F
zurückgibt, ohne zu wissen, welcher Parameter es gegeben wird und ich nicht weiß das, weil ich nicht weiß, was G
zurückgibt.
Ich bin mir ziemlich sicher, dass ich ein neues Function
Konzept benötigen, die nicht über den Rückgabetyp als meine Komposition Funktion kümmert sich nicht darum, was F
kehrt scheren, so lange, wie es aufrufbare ist. Und ich denke, ich könnte die Einschränkung auf das innere Lambda setzen, das der Parameter für G und damit für F gibt und korrigiert, aber das bedeutet, dass ich nicht zusammensetzbare Funktionen schreiben kann und bis zur Aufrufstelle keinen Fehler bekommen werde. Ist das vermeidbar?
Vielleicht so etwas wie:
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...));
}
}
Ist dies das Beste, was ich tun kann (wenn ich auch das tun können)?
Dank ja das sieht aus wie die Lösung. Es ist eine Schande, weil ich die Tatsache nicht mag, dass ich zwei nicht aufrufbare Objekte ohne einen Konzeptfehler zusammensetzen kann. Gibt es da überhaupt eine Callable-Variante des Callbacks, bei der die Argumenttypen nicht vorab benötigt werden? –
@SamKellett Nicht out of the box. Sie können sich dafür entscheiden, ein Protokoll einzuhalten, bei dem Funktionsobjekte ihre "Signatur" oder etwas, das diesem nahe steht, zur Verfügung stellen, aber es ist ein großes Unterfangen ohne offensichtlichen Nutzen. –
fair, danke für die Antwort –