Is there a copyable function wrapper in C++23 with support for const/ref/noexcept?
Asked Answered
E

1

8

C++23 introduces std::move_only_function which has support for const and l/r-value-reference on the implicit this parameter and noexcept(true/false) on the function itself.

The old std::function is lacking these overloads.

#include <functional>

int main(){
    std::function<void()>([]noexcept(true){});          // okay ✓
    std::function<void()>([]noexcept(false){});         // okay ✓
    std::function<void()noexcept>([]noexcept(true){});  // not supported
    std::function<void()noexcept>([]noexcept(false){}); // not supported

    std::move_only_function<void()>([]noexcept(true){});          // okay ✓
    std::move_only_function<void()>([]noexcept(false){});         // okay ✓
    std::move_only_function<void()noexcept>([]noexcept(true){});  // okay ✓
    std::move_only_function<void()noexcept>([]noexcept(false){}); // fails ✓

    std::function<void()>([i=0]{});             // okay ✓
    std::function<void()>([i=0]mutable{});      // okay ✓
    std::function<void()const>([i=0]{});        // not supported
    std::function<void()const>([i=0]mutable{}); // not supported

    std::move_only_function<void()>([i=0]{});             // okay ✓
    std::move_only_function<void()>([i=0]mutable{});      // okay ✓
    std::move_only_function<void()const>([i=0]{});        // okay ✓
    std::move_only_function<void()const>([i=0]mutable{}); // fails ✓
}

Unfortunately, as the name suggests, std::move_only_function cannot be copied.

#include <functional>
#include <vector>

int main(){
    auto const fn = []{};

    std::function<void()> a = fn;
    std::vector<std::function<void()>> a_list{a, a};

    std::move_only_function<void()> b = fn;
    std::vector<std::move_only_function<void()>> b_list{b, b}; // error
}

Is there an analog function wrapper that supports copying? If this is not the case in C++23, is there a library that provides this?

I need a data type that is the owner of the function.

Endoplasm answered 15/3, 2023 at 18:30 Comment(9)
Then just use the std::function. The additional cv-ref-noexcept qualifiers are unnecessary in std::function for the most part. You still haven't clarified why you need the function qualifiers, it seems unnecessary to me.Jansenism
@Jansenism Because I want to call the function wrapper object from a noexcept function of course. This function reads the callbacks from a queue and all callbacks are required to not throw any exceptions. With move_only_function I can make it a compile time error if a user tries to add a non-noexcept function to the queue, with std::function I need to trust the user to do the right thing as documented.Endoplasm
Do you realize that copying a std::function may throw an exception? How exactly requiring that the operator () is noexcept is helpful here?Jansenism
@Jansenism The copying happens in the part that sets up the queue. This is not a problem. The user can catch the exception in this case normally and decide for himself how he wants to react to it.Endoplasm
now I am confused. Why do you even need the copying for then? Just the std::move_only_function.Jansenism
To me it looks like you have an XY problem. You are asking the wrong question here. You don't need copying on your side, and I don't see any reason why copying would be needed on the user's side of the queue either. You'd better fix whatever mess happens on user's side so copying isn't needed. Also, I habe serious doubts that requiring user to supply noexcept callables would help. They'll just end up marking functions noexcept regardless of possible exceptions, and perhaps file a bunch of bug reports for noreason just because code doesn't compile.Jansenism
@Jansenism I am not allowed or able to show you our code here. But the accepted answer shows that what I am looking for is currently standardized. I think that is proof enough that the use case exists and is also not uncommon. ;-)Endoplasm
the papper only shows that some people wants it standardized, but it doesn't mean that it will ever be. The document lacks motivation/usecase for the addition besides uniformity with std::move_only_function which is introduced in C++23...Jansenism
@Jansenism I added additional examples regarding const instead of noexcept. Maybe this is simpler to understand …Endoplasm
P
7

Is there an analog function wrapper that supports copying? If this is not the case in C++23, is there a library that provides this?

No.

In C++26 there will be std::copyable_function (P2548). There is a reference implementation.

Punt answered 15/3, 2023 at 19:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.