Repository navigation
Conversation
A function's constructor takes each curried argument as
`__curried_param_t<Arg>`, which is `Arg const &` or `Arg &&` depending on
whether `Arg` is trivially copy- and move-constructible. Those parameter
types are computed in `__function_meta` and passed to `__function` as
its `_Params` template argument, so merely naming a function evaluates
the traits, which needs every curried parameter's type to be complete.
A class therefore can't name a function that curries an object of the
class in its own definition, e.g. as the return type of a member
function declared there:
struct base {
exec::function<ex::sender_tag(base), sigs> copied(this base self);
};
This diff names functions with curried arguments with a
`__deferred_params` marker in place of the parameter types. The
specialization of `__function` for the marker wraps the specialization
for the computed parameter types, as a `[[no_unique_address]]` member,
and forwards to it, so the types are computed only when the function is
instantiated. A function with no curried arguments has nothing to
compute and keeps naming `__mlist<>` directly.
The wrapper's constructor expands `__curried_param_t<_Args>...` in its
parameter list. That's the shape `_Params` was introduced to avoid,
because nvc++'s name mangler fails on it, but only when the pack is
empty and is followed by a deduced parameter, and the wrapper is never
used with no curried arguments. The member-function form goes back to
expanding the alias too, after its leading `_Self &&` parameter, and
also names the marker, so its curried parameters may also be
incomplete when it's named.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`function` rejects `sender_tag(Args...) &&` and `sender_tag(Args...) const &&`, on the theory that a `function` taking its implicit object as an rvalue would borrow an object that's about to expire. But value category is not lifetime: a `const &` function binds a temporary just as easily, and `std::move(obj).get(key)` is fine whenever `obj` outlives the operation. So this diff accepts both forms, optionally `noexcept`. As for the lvalue forms, the constructor stores a pointer to the object; it takes the object as an rvalue, and the factory receives it as one, so the factory can move from it. A `const &&` function also accepts a non-const rvalue, as a `const &` one accepts a non-const lvalue. The `__function_meta` specializations for member-function call types now all derive from the specialization for the non-member call type with the same return type, parameters and `noexcept`-ness, adding only the binding of the implicit object, rather than repeating the whole description for each qualifier. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ispeters
force-pushed
the
accept-rvalue-implicit-objects
branch
from
October 29, 2026 02:30
916b631 to
9dabacc
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
functionrejectssender_tag(Args...) &&andsender_tag(Args...) const &&, on the theory that afunctiontaking its implicit object as an rvalue would borrow an object that's about to expire. But value category is not lifetime: aconst &function binds a temporary just as easily, andstd::move(obj).get(key)is fine wheneverobjoutlives the operation. So this diff accepts both forms, optionallynoexcept. As for the lvalue forms, the constructor stores a pointer to the object; it takes the object as an rvalue, and the factory receives it as one, so the factory can move from it. Aconst &&function also accepts a non-const rvalue, as aconst &one accepts a non-const lvalue.The
__function_metaspecializations for member-function call types now all derive from the specialization for the non-member call type with the same return type, parameters andnoexcept-ness, adding only the binding of the implicit object, rather than repeating the whole description for each qualifier.Depends on #2370