Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

<functional>: std::not_fn can accept non-movable function #4048

Closed
hewillk opened this issue Sep 24, 2023 · 2 comments · Fixed by #4057
Closed

<functional>: std::not_fn can accept non-movable function #4048

hewillk opened this issue Sep 24, 2023 · 2 comments · Fixed by #4057
Labels
bug Something isn't working

Comments

@hewillk
Copy link
Contributor

hewillk commented Sep 24, 2023

It seems that std::not_fn should reject the following code according to [func.not.fn]:

Mandates: is_constructible_v<FD, F> && is_move_constructible_v<FD> is true.

godbolt:

#include <functional>

struct OnlyCopyableFun {
  OnlyCopyableFun() = default;
  OnlyCopyableFun(const OnlyCopyableFun&) = default;
  OnlyCopyableFun(OnlyCopyableFun&&) = delete;
  bool operator()(auto) const;
};

int main() {
  OnlyCopyableFun f;
  auto nf = std::not_fn(f); // only ill-formed in libc++
}

Feel free to correct me if I've missed something.
Not quite sure why these standard call wrapper factories (std::bind_front, std::bind, etc.) require all argument types to be move-constructible, although the call wrapper produced in the above example is still move-constructible as its underlying type has a copy constructor.
It seems to me that just requiring is_constructible_v<FD, F> is enough, which is what the range adaptor object does.

@frederick-vs-ja
Copy link
Contributor

I think we should file an LWG issue to reduce the Mandates and Preconditions of these functions.

@StephanTLavavej StephanTLavavej added LWG issue needed A wording defect that should be submitted to LWG as a new issue bug Something isn't working and removed LWG issue needed A wording defect that should be submitted to LWG as a new issue labels Sep 27, 2023
@StephanTLavavej
Copy link
Member

@CaseyCarter noted that the Standard (via the "call wrapper" phrase of power that I forgot about) requires not_fn() to produce something that's Cpp17MoveConstructible, so the Mandates on it makes sense and its presence isn't a defect.

N4958 [func.require]/3: "Every call wrapper meets the Cpp17MoveConstructible and Cpp17Destructible requirements. An argument forwarding call wrapper is a call wrapper [...]"

/4: "A perfect forwarding call wrapper is an argument forwarding call wrapper that [...]"

[func.not.fn]/4 "Returns: A perfect forwarding call wrapper"

Therefore, this is an implementation issue where we should be static_asserting explicitly, instead of assuming that the implementation will "naturally diagnose" the requirement which is not the case here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants