From 9b608d68eb792098b3a23fa6521770bacb86f878 Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Mon, 28 Sep 2026 20:35:16 +0100 Subject: [PATCH 1/2] Allow `void`-returning callbacks in `transform` over a copack Represent void callback results as pack<> in the result copack, including transform_error over a copack error. Add copack_value() for expected. Convert results before spliced arguments expire and include the selected overload's explicit conversion in noexcept. Mutable operands can now select a void overload where they previously fell back to a valued const overload. Assisted-by: Claude:claude-opus-5-5 Assisted-by: Codex:gpt-6-astra --- CHANGELOG.md | 8 ++ docs/reference/expected.md | 17 +++- include/fn/copack.hpp | 113 +++++++++++++++++------ include/fn/expected.hpp | 35 ++++++-- tests/fn/copack.cpp | 117 ++++++++++++++++++++++-- tests/fn/expected.cpp | 168 ++++++++++++++++++++++++++++++++--- tests/fn/just_choice.cpp | 28 ++++-- tests/fn/optional.cpp | 25 ++++++ tests/fn/transform.cpp | 49 +++++++++- tests/fn/transform_error.cpp | 42 ++++++++- 10 files changed, 537 insertions(+), 65 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38376c58..71e5c180 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ Design history of libfn, newest first. The living documents — [README.md](README.md), [CONTRIBUTING.md](CONTRIBUTING.md), [docs/](docs/) — describe only the present state of the design; when a decision makes an earlier idea obsolete, this file is where the transition is recorded and explained. +## `transform` over a copack maps a `void` result to `pack<>` — 27 September 2026 + +`transform` over a copack represents `void` callback results as `pack<>`. Mixed `void` and `int` results yield `copack_for, int>`; all-`void` results yield `copack>`. This applies through `expected`, `optional` and `choice`, and to `transform_error` over a copack error. Plain error types still reject `void` results. Mutable operands can select a `void` overload where they previously fell back to a valued `const` overload. + +Results are converted before spliced arguments expire, fixing a dangling reference. The `noexcept` specification includes the selected overload's explicit result conversion. + +`expected::copack_value()` lifts to `expected>, E>`. + ## `and_then` joins `void` and valued branches through `pack<>` — 26 September 2026 `and_then` accepts branches returning both `void`-valued and valued `expected` results. For example, `A -> expected` and `B -> expected` join as `expected, int>, E>`; this previously failed to compile. An all-`void` join stays `void`. diff --git a/docs/reference/expected.md b/docs/reference/expected.md index 28d790aa..2698b7ed 100644 --- a/docs/reference/expected.md +++ b/docs/reference/expected.md @@ -290,6 +290,15 @@ constexpr auto copack_value() const && -> decltype(auto); :include-doxygen-doc-params: fn::expected::copack_value { args: "", title: "parameters" } +```cpp {title: "fn::expected< void, Err >::copack_value"} +constexpr auto copack_value() const & -> expected>, error_type>; // (1) +constexpr auto copack_value() && -> expected>, error_type>; // (2) +``` + +:include-doxygen-doc: fn::expected< void, Err >::copack_value { args: "" } + +:include-doxygen-doc-params: fn::expected< void, Err >::copack_value { args: "", title: "parameters" } + ## and_then {style: "api"} ```cpp {title: "fn::expected::and_then"} @@ -517,10 +526,10 @@ constexpr auto copack_error(some_expected auto &&src) -> decltype(auto); // (1) :include-doxygen-doc-params: fn::copack_error { args: "some_expected auto &&", title: "parameters" } ```cpp {title: "fn::copack_value"} -constexpr auto copack_value(some_expected_non_void auto &&src) -> decltype(auto); // (1) -constexpr auto copack_value(some_optional auto &&src) -> decltype(auto); // (2) +constexpr auto copack_value(some_expected auto &&src) -> decltype(auto); // (1) +constexpr auto copack_value(some_optional auto &&src) -> decltype(auto); // (2) ``` -:include-doxygen-doc: fn::copack_value { args: "some_expected_non_void auto &&" } +:include-doxygen-doc: fn::copack_value { args: "some_expected auto &&" } -:include-doxygen-doc-params: fn::copack_value { args: "some_expected_non_void auto &&", title: "parameters" } +:include-doxygen-doc-params: fn::copack_value { args: "some_expected auto &&", title: "parameters" } diff --git a/include/fn/copack.hpp b/include/fn/copack.hpp index 71a1d5da..7749292c 100644 --- a/include/fn/copack.hpp +++ b/include/fn/copack.hpp @@ -104,11 +104,7 @@ template