Skip to content

invocable_transform_error hard-errors (instead of yielding false) for a void-returning callback #290

Description

@Bronek

fn::invocable_transform_error with a void-returning callback is a hard compile error rather than false. The first disjunct asks

{ ::fn::invoke(FWD(fn), FWD(v).error()) } -> convertible_to_unexpected;

and convertible_to_unexpected<void> (include/fn/concepts.hpp:72) instantiates pfn::unexpected<void>, whose validity mandate is a class-body static_assert (include/pfn/expected.hpp:125) — it fires during instantiation, outside any immediate context, so no enclosing requires-expression can absorb it.

Consequence for user code: e | transform_error([](Error) {}) hard-errors where every sibling verb SFINAE-drops an unusable callback. The contrast with transform is sharp: there a void return is legitimate (it transforms the value side to expected<void, E>), and convertible_to_expected (concepts.hpp:82) carries an explicit same_as<T, void> arm for exactly that reason. convertible_to_unexpected has no such guard, and for it void can never be valid — the concept just needs to say so instead of exploding.

Nine-line repro, verified on g++ 14.3.0 and clang++ 16.0.6 — identical failure, both naming the unexpected<void> mandate (g++ follows up with forming reference to void from the void instantiation's error() const &):

#include <fn/transform_error.hpp>

struct Error final {};
constexpr auto fnVoid = [](Error) -> void {};

static_assert(not fn::invocable_transform_error<decltype(fnVoid), fn::expected<int, Error>>);

int main() { return 0; }

Fix direction: mirror convertible_to_expected's void handling — e.g. concept convertible_to_unexpected = (not ::std::is_void_v<::std::remove_cvref_t<T>>) && requires { ... }; — one conjunct in concepts.hpp, after which the repro's static_assert holds.

Same class as #277 (validity surfacing where it hard-errors instead of in a constraint that yields false), though the mechanism here is a mandate inside a concept rather than a deduced-return body. Found while probing the verb concepts on the #85 branch; tests/fn/transform_error.cpp carries a GAP comment at the probe site that cites this issue and gains a real negative probe once fixed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    release-0.1Planned for release 0.1

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions