Skip to content

can a sender's connect member fn be private if it befriends execution::connect_t? #342

Open

Description

@ericniebler

can a user expect this to work?

#include <execution>

struct Sender
{
  using sender_concept = std::execution::sender_t;

private:
  friend std::execution::connect_t;

  auto connect( std::execution::receiver auto rcvr )
  {
    //...
  }
};

int main()
{
  auto op = std::execution::connect(Sender{}, SomeReceiver{});
}

the current wording suggests it should work but it is not guaranteed. should it be?

same question about get_env and get_completion_signatures — although the latter is complicated by the fact that there is no get_completion_signatures_t to befriend.

Activity

  1. added
    enhancementNew feature or request
    discussionWe need to talk about this; there's nothing actionable here yet
    on Jul 3, 2025
  2. dietmarkuehl commented on Jul 3, 2025

    @dietmarkuehl
    Collaborator

    I have implemented various members as private making the CPO a friend: that is akin making virtual functions protected and forwarding from a public (inline) function. That is very useful when adding instrumentation which should apply to all uses of a customization.

    The real question is, in my mind the opposite one: should a user be allowed to write Sender{}.connect(SomeReceiver{})? …and I think the answer should be “no!” This also applies to start, set_value, etc.

  3. ericniebler commented on Jul 3, 2025

    @ericniebler
    CollaboratorAuthor

    should a user be allowed to write Sender{}.connect(SomeReceiver{})?

    i agree this is a better framing. of course, of Sender is a type they control, then we can't tell people to not call connect directly on it. but we can say that if Sender is library-provided, they cannot.

    a related question is whether we want to allow execution::connect to, say, wrap the returned operation state for some reason. in which case, connect(sndr, rcvr) would not be equivalent to sndr.connect(rcvr).

  4. ispeters commented on Jul 4, 2025

    @ispeters
    Collaborator

    a related question is whether we want to allow execution::connect to, say, wrap the returned operation state for some reason. in which case, connect(sndr, rcvr) would not be equivalent to sndr.connect(rcvr).

    That (connect wrapping sndr.connect(rcvr)) is how Unifex implements async stacks so I think that should be left open as an implementation option.

  5. lewissbaker commented on Jul 4, 2025

    @lewissbaker
    Collaborator

    a related question is whether we want to allow execution::connect to, say, wrap the returned operation state for some reason. in which case, connect(sndr, rcvr) would not be equivalent to sndr.connect(rcvr).

    It is already the case that connect(sndr, rcvr) may not be the same as sndr.connect(rcvr) because connect(sndr, rcvr) applies transform_sender(sndr, get_env(rcvr)) before then trying to call .connect(rcvr) member function.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2designdiscussionWe need to talk about this; there's nothing actionable here yetenhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions