diff --git a/src/lib/result.hpp b/src/lib/result.hpp index d9081f269..45724de61 100644 --- a/src/lib/result.hpp +++ b/src/lib/result.hpp @@ -30,6 +30,7 @@ ** this kind of API design however is anything than trivial, given that ** any value can be thrown as exception in C++ ** @see vault::ThreadJoinable usage example + ** @see Result_test */ @@ -40,7 +41,6 @@ #include "lib/error.hpp" #include "lib/item-wrapper.hpp" #include "lib/meta/util.hpp" -#include "lib/null-value.hpp" #include #include @@ -51,43 +51,13 @@ namespace lib { namespace error = lumiera::error; - - /** - * Helper to invoke an arbitrary callable in a failsafe way. - * @param capturedFailure *reference* to a std::exeption_ptr served by side-effect - * @param callable anything std::invoke can handle - * @return _if_ the invokable has a return type, the result is returned, - * _otherwise_ this is a void function - * @todo with C++20 the body of the implementation can be replaced by std::invoke_r //////////////////////TICKET #1245 - */ - template - inline auto - failsafeInvoke (std::exception_ptr& capturedFailure - ,FUN&& callable - ,ARGS&& ...args) noexcept - { - using Res = std::invoke_result_t; - try { - capturedFailure = nullptr; - if constexpr (std::is_void_v) - std::invoke (std::forward(callable), std::forward(args)...); - else - return std::invoke (std::forward(callable), std::forward(args)...); - } - catch(...) - { - capturedFailure = std::current_exception(); - if constexpr (not std::is_void_v) - return lib::NullValue::get(); - } - } - /** * Representation of the result of some operation, _EITHER_ a value or a failure. * It can be created for passing a result produced by the operation, or the failure * to do so. The value can be retrieved by implicit or explicit conversion. + * @tparam RES the nominal result type to be captured from the function invocation. * @throw error::State on any attempt to access the value in case of failure * @warning this class has a lot of implicit conversions; * care should be taken when defining functions @@ -123,9 +93,16 @@ namespace lib { Result (FUN&& callable, ARGS&& ...args) noexcept : failure_{} { - failsafeInvoke (failure_ - ,std::forward (callable) - ,std::forward(args)...); + try { + static_assert (std::is_invocable_v); + std::invoke (std::forward(callable) + ,std::forward(args)... + ); + } + catch(...) + { + failure_ = std::current_exception(); + } } explicit @@ -173,10 +150,19 @@ namespace lib { template>> Result (FUN&& callable, ARGS&& ...args) noexcept : Result{true} - , value_{failsafeInvoke (failure_ - ,std::forward (callable) - ,std::forward(args)...)} - { } + , value_{} + { + try { + static_assert (std::is_invocable_r_v); + value_ = std::invoke_r (std::forward(callable) + ,std::forward(args)... + ); + } + catch(...) + { + failure_ = std::current_exception(); + } + } // is or is not copyable depending on RES @@ -220,7 +206,7 @@ namespace lib { /** deduction guide: find out about result value to capture from a generic callable. */ template Result (FUN&&, ARGS&&...) -> Result>; - + } // namespace lib diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index f6dcfde22..7d75eae0b 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -76032,6 +76032,42 @@ + + + + + + + + + + + +

+ Es könnte in der Tat so funktionieren; +

+

+ ....mir fehlte aber komplett der Widerhalt und Anker in dem, was denn vom Builder gebaut werden soll. Für einen klassischen Compiler dagegen ist genau dieser Teil ganz fest vorgegeben, in der Form des Maschinencodes, der vom Compiler erzeugt werden muß. Ein Compiler ist eine Maschinerie, insofern er eine eigene Innen-Logik hat, welche nur lose mit dem Zweck verbunden ist, dem sie dient. So etwas baut man, indem man von Bekanntem ausgeht, und es daraufhin prüft, ob es passend gemacht werden kann. Fest steht dabei eine Grundstruktur, hier das Schema aus Integrations-Schritten, die jewelis als Durchgang über die gesamte Datenstruktur zu bewerkstelligen sind. Auch bezüglich der Methode, eine Abstraktion einzuziehen zwischen der Mechanik der Daten-Traversierung und der eigentlichen Daten-Transformation — diese Methode steht außer Zweifel.... +

+

+ Was bisher fehlte, war einfach die Möglichkeit, mit der echten Arbeit an diesem Thema beginnen zu können; daher bleibt der bestehende Code auf dem Rang einer Programmier-Übung stehen (und es war angemessen, ihn einfach liegenzulassen) +

+ +
+
+ + + + + + + + + + + + +
@@ -162197,7 +162233,7 @@ actively maintained upstream. Please remove gdl from Debian. - + @@ -165857,8 +165893,8 @@ Since then others have made contributions, see the log for the history.
- - + + @@ -165875,8 +165911,8 @@ Since then others have made contributions, see the log for the history.
- - + + @@ -166991,7 +167027,7 @@ Since then others have made contributions, see the log for the history.
- + @@ -167012,7 +167048,7 @@ Since then others have made contributions, see the log for the history. - + @@ -167080,9 +167116,32 @@ Since then others have made contributions, see the log for the history. - - - + + + + + + + + + +

+ Der erste Entwurf für eine Infrastruktur für den Builder/Compiler (der Kern von Lumiera) hängt völlig in der Luft, und war von Phantasie-Vorstellungen getragen, wie ich mir diesen Kern gerne vorstellen würde. Ich war (und bin eigentlich immer noch) vom Visitor fasziniert, hab aber den Verdacht, daß das gar nicht das ist, was ich darunter verstehe. Soweit so gut. Habe dann seinerzeit rein auf Verdacht einen eigenen Visitor implementiert, und dann beim Integrationsversuch gemerkt, daß er gar nicht auf mein Modell paßt. Die Notrettung war ein »wrapper-pointer«, und der brauchte eine Variant-Storage. Boost zieht die ganze MPL mit rein, keine Ahnung warum, aber ich kann das besser. Der zweite Versuch, das Gleiche zu bauen wurde dann nur noch eine halb-Katastrofe und ist jetzt in unserer Support-Lib (und hie und da im Einsatz) +

+ +
+
+ + + + +

+ ....und zwar sehr bald, wenn ich den Builder in Angriff nehme — was ich nun nicht mehr hinausschieben kann. Aber dieses aktuelle »Vertical Slice« geht noch ohne, und damit lasse ich die Finger davon; es zeichnet sich bereits ab, daß ich mein high-Level-Model nochmal komplett umkrempele und nicht mehr auf Shared-Pointer aufbauen werde, und so könnte das mit dem Visitor ja vielleicht doch noch klappen. +

+ +
+
+
@@ -167115,15 +167174,14 @@ Since then others have made contributions, see the log for the history.constexpr sein

- - +
- + @@ -167183,8 +167241,7 @@ Since then others have made contributions, see the log for the history. - - + @@ -167461,8 +167518,8 @@ Since then others have made contributions, see the log for the history. - - + + @@ -167472,8 +167529,18 @@ Since then others have made contributions, see the log for the history. + + + + +

+ ...weil wir nun nämlich den gewünschten Return-Typ von oben durchgeben können, und nicht mehr per Type-Trait inferieren müssen; außerdem ist das ganze Thema Invoke / convert nun in die Standardlibrary ausgelagert (und ja, die hat deswegen ganz schön zu rudern) +

+ +
- + + @@ -167482,6 +167549,46 @@ Since then others have made contributions, see the log for the history. + + + + + + + + +

+ ...wir brauchen diesen Aufruf nämlich nie, aber wir brauchen ihn, damit die Funktion durch den Compiler geht. Die einzige Alternative, die ich sehe, wäre, die Invocation wieder in die Hauptklasse zu integrieren, incl. try/catch. Dann müßte ich aber das Ergebnis auch stets an einen zunächst leer konstruierten ItemWrapper zuweisen — was dank der speziellen Konstruktion des ItemWrappers tatsächlich möglich wäre (er mach in diesem Fall eine Move-Konstruktion) +

+ +
+ +
+ + + + + + +

+ ...denn diese war ja nur notwendig geworden, um den void-Fall mit zu integrieren; also genau das, was nun invoke_r aus der STDLib auch leistet. Damit hätten wir dann zweimal das try-catch-Konstrukt, aber das verbessert hier eigentlich die Lesbarkeit, da man nun direkt sehen kann, was passiert. +

+ +
+
+ + + + +

+ Damit wird der Aufruf ein Einzeiler, und das Problem mit der void-Fallunterscheidung fällt ebenfalls flach +

+ +
+
+ + +