First draft: Non-copyable call wrapper, std::unique_function

224 views
Skip to first unread message

David Krauss

unread,
May 19, 2015, 12:07:03 PM5/19/15
to std-pr...@isocpp.org
Here’s a first draft of a non-copyable polymorphic call wrapper proposal: http://bit.ly/uniqfun

This proposal describes a variation of std::function supporting non-copyable target objects. It removes the copy constructor, and adds in-place construction of target objects.

All comments welcome. Doesn’t look too scary, I just might prototype it.

Inspired by the recent discussion, "smart function pointer proposal."

Casey Carter

unread,
May 19, 2015, 1:26:34 PM5/19/15
to std-pr...@isocpp.org

On Tuesday, May 19, 2015 at 11:07:03 AM UTC-5, David Krauss wrote:
Here’s a first draft of a non-copyable polymorphic call wrapper proposal: http://bit.ly/uniqfun

unique_function would probably be more useful if it had operator(). Joking aside, there should probably be three overloads qualified by &, const&, and && respectively. That way you both avoid std::function's threadsafety problems (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4348.html) and enable unique_function to usefully hold "one-shot" functions.

Nicol Bolas

unread,
May 19, 2015, 1:42:34 PM5/19/15
to std-pr...@isocpp.org
On Tuesday, May 19, 2015 at 12:07:03 PM UTC-4, David Krauss wrote:
Here’s a first draft of a non-copyable polymorphic call wrapper proposal: http://bit.ly/uniqfun

It'd probably be a good idea to let someone know if a link goes to Dropbox to download a PDF, or if it's just a HTML page on the web. You know, without having to click the link.

This proposal describes a variation of std::function supporting non-copyable target objects. It removes the copy constructor, and adds in-place construction of target objects.

All comments welcome. Doesn’t look too scary, I just might prototype it.

Well, that would help. At least it would let us know the kind of work that would be involved in doing a move-transfer from `function` to `unique_function`. The concern there being the changes to `function`'s implementation that would need to be made.

On the proposal, I think the idea of a `unique_any` could be valuable. I'm not sure if a non-moveable `unique_any` could be useful by someone, but it's possible.

But I don't like the idea of considering `any`s to be at all equivalent to or transformable between `function`s. While their implementations are very similar, the objects are conceptually quite distinct. Just like `vector` and `string`. As such, I don't think we should explicitly support transforming one into the other.

I see you have `allocate_assign` and `emplace_assign`. It seems to me that you should follow the existing std::function convention. `allocate_assign` is conceptually equivalent to `function::assign`, so you should probably just call it that. Also, I see no reason why it shouldn't also be able to work like `function::assign`. Similarly, `emplace_assign` should simply be called `emplace`. These sound more like the standard

I'm going to assume that you intended to add an `operator()` overload in there somewhere. ;) However, unlike Casey Carter, I would not suggest attempting to fix the thread safety problem until the committee has decided how they're going to fix it in `std::function`. We don't want two completely different fixes involved.

That's not to say that something shouldn't be done. It's more to say that this proposal should hold off on committing to any one solution until more is known.

Lastly, bikeshedding. I'm not sure that `unique` is the right word. Oh, it conjures up thoughts of `unique_ptr`, which makes you think "move only". But `unique_ptr` is about ownership of memory, while `unique_function` is just about being a move-only function wrapper. At the same time, I cannot come up with a more explicit name that doesn't sound silly (like `move_only_function`).

Matt Calabrese

unread,
May 19, 2015, 1:48:25 PM5/19/15
to std-pr...@isocpp.org
Please no, as this would require type erasing all of those. I've been working on a similar effort and my personal thoughts are that the qualification should be specified as a part of the function type, with exactly one signature being erased (and that signature being reflected at the top-level as well):

unique_function<void() const> // for operator() const
unique_function<void() &&> // for operator() &&

Do not type-erase more than is necessary as it can force compile errors even when the operations are not actually used (and cause bloating, but this is probably not as important to worry about). It's the same reason we need a move-only function even though you might not ever actually use the copy operation when you put something that is move only into it. Don't type erase more than what you need. Keep the requirements minimal.

Nevin Liber

unread,
May 19, 2015, 1:50:05 PM5/19/15
to std-pr...@isocpp.org
On 19 May 2015 at 12:42, Nicol Bolas <jmck...@gmail.com> wrote:

On the proposal, I think the idea of a `unique_any` could be valuable. I'm not sure if a non-moveable `unique_any` could be useful by someone, but it's possible.

Can't you always make unique_any moveable, given that it can allocate in the heap?

Also, consider making unique_function(unique_function&&) noexcept.
--
 Nevin ":-)" Liber  <mailto:ne...@eviloverlord.com(847) 691-1404

Matt Calabrese

unread,
May 19, 2015, 1:52:16 PM5/19/15
to std-pr...@isocpp.org
On Tue, May 19, 2015 at 10:49 AM, Nevin Liber <ne...@eviloverlord.com> wrote:
Also, consider making unique_function(unique_function&&) noexcept.

+1 for noexcept, and it should be able to avoid calling the move constructor when in remote storage (forcing remote storage if the underlying object has a move constructor that can throw)

Nicol Bolas

unread,
May 19, 2015, 3:40:53 PM5/19/15
to std-pr...@isocpp.org


On Tuesday, May 19, 2015 at 1:50:05 PM UTC-4, Nevin ":-)" Liber wrote:
On 19 May 2015 at 12:42, Nicol Bolas <jmck...@gmail.com> wrote:

On the proposal, I think the idea of a `unique_any` could be valuable. I'm not sure if a non-moveable `unique_any` could be useful by someone, but it's possible.

Can't you always make unique_any moveable, given that it can allocate in the heap?

Oh, I wasn't saying that `unique_any` should be non-moveable. I was referring to the way that `unique_function` allows the storage of non-moveable types, and I was saying that this feature probably won't be as useful to `unique_any`.
 
Also, consider making unique_function(unique_function&&) noexcept.


Well, the reason it's not noexcept is that `unique_function` is allowed to store non-moveable types. And since the type is erased (unlike, say, non-moveable std::vector), the only way to signal an error when you attempt to move it is to throw an exception.

That being said, I don't think the benefits of being able to store immobile functions outweight the benefits of having noexcept move constructor/assignment.

Matt Calabrese

unread,
May 19, 2015, 3:47:15 PM5/19/15
to std-pr...@isocpp.org
On Tue, May 19, 2015 at 12:40 PM, Nicol Bolas <jmck...@gmail.com> wrote:
Well, the reason it's not noexcept is that `unique_function` is allowed to store non-moveable types. And since the type is erased (unlike, say, non-moveable std::vector), the only way to signal an error when you attempt to move it is to throw an exception.

That being said, I don't think the benefits of being able to store immobile functions outweight the benefits of having noexcept move constructor/assignment.

Or just don't require invocation of the move constructor since you can, instead, copy the pointer to it if it's in remote storage (and you just force remote storage if the operation isn't noexcept, even if it fits in the small object storage). I don't buy the "what if the move constructor has side effects so we must call it" standpoint, since the language already allows things like copy/move elision for return value and argument passing. You can implement no-except move even if the type-erased object has a move constructor that can throw.

FWIW, I'm pretty sure the proposed std::any has noexcept move operations.

Nevin Liber

unread,
May 19, 2015, 4:03:32 PM5/19/15
to std-pr...@isocpp.org
On 19 May 2015 at 14:40, Nicol Bolas <jmck...@gmail.com> wrote:
Well, the reason it's not noexcept is that `unique_function` is allowed to store non-moveable types. And since the type is erased (unlike, say, non-moveable std::vector), the only way to signal an error when you attempt to move it is to throw an exception. 

The libc++ version of std::function has a noexcept move constructor, and other implementers are looking to follow suit. 

Nevin Liber

unread,
May 19, 2015, 4:07:00 PM5/19/15
to std-pr...@isocpp.org
On 19 May 2015 at 14:47, 'Matt Calabrese' via ISO C++ Standard - Future Proposals <std-pr...@isocpp.org> wrote:
On Tue, May 19, 2015 at 12:40 PM, Nicol Bolas <jmck...@gmail.com> wrote:
Well, the reason it's not noexcept is that `unique_function` is allowed to store non-moveable types. And since the type is erased (unlike, say, non-moveable std::vector), the only way to signal an error when you attempt to move it is to throw an exception.

That being said, I don't think the benefits of being able to store immobile functions outweight the benefits of having noexcept move constructor/assignment.

Or just don't require invocation of the move constructor since you can, instead, copy the pointer to it if it's in remote storage (and you just force remote storage if the operation isn't noexcept, even if it fits in the small object storage). I don't buy the "what if the move constructor has side effects so we must call it" standpoint, since the language already allows things like copy/move elision for return value and argument passing.

Worse, if you required it, you'd have to do a second heap allocation for moves that couldn't be embedded in the unique_function object just to call it.  Ugh.

Nicol Bolas

unread,
May 19, 2015, 4:16:47 PM5/19/15
to std-pr...@isocpp.org

Right. Obviously. Sorry, wasn't paying attention.

So yes, make it noexcept.

David Krauss

unread,
May 19, 2015, 7:16:23 PM5/19/15
to std-pr...@isocpp.org

> On 2015–05–20, at 1:26 AM, Casey Carter <cart...@gmail.com> wrote:
>
> unique_function would probably be more useful if it had operator(). Joking aside, there should probably be three overloads qualified by &, const&, and && respectively. That way you both avoid std::function's threadsafety problems (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4348.html) and enable unique_function to usefully hold "one-shot" functions.

I’m writing a separate proposal for that.

David Krauss

unread,
May 19, 2015, 8:09:09 PM5/19/15
to std-pr...@isocpp.org
On 2015–05–20, at 1:42 AM, Nicol Bolas <jmck...@gmail.com> wrote:

On Tuesday, May 19, 2015 at 12:07:03 PM UTC-4, David Krauss wrote:
Here’s a first draft of a non-copyable polymorphic call wrapper proposal: http://bit.ly/uniqfun

It'd probably be a good idea to let someone know if a link goes to Dropbox to download a PDF, or if it's just a HTML page on the web. You know, without having to click the link.

Ah. It’s a PDF. I tried to put the extension inside the link, but for some reason Bitly doesn’t allow it.

Well, that would help. At least it would let us know the kind of work that would be involved in doing a move-transfer from `function` to `unique_function`. The concern there being the changes to `function`'s implementation that would need to be made.

Unfortunately, prototyping it once will only provide information about one std::function implementation.

Having reviewed GNU’s, I think will involve adding a __move_functor verb after __clone_functor, which may already be needed for conformance: It never calls the target move constructor, but [func.wrap.func.con]/11 mentions doing so.

But I’m still at square one: I’ll probably do it as a Clang extension, because their license allows other implementations to borrow.

But I don't like the idea of considering `any`s to be at all equivalent to or transformable between `function`s. While their implementations are very similar, the objects are conceptually quite distinct. Just like `vector` and `string`. As such, I don't think we should explicitly support transforming one into the other.

That sort of thing will only be proposed later. I think the use-case could become more apparent following a first round of extensions.

For now, I’m only using the any name in the common interfaces. Alternate names would be appreciated.

I see you have `allocate_assign` and `emplace_assign`. It seems to me that you should follow the existing std::function convention. `allocate_assign` is conceptually equivalent to `function::assign`, so you should probably just call it that.

I guess so. I don’t like how assign always requires an allocator, and reverses the order of arguments compared to the constructor.

Also, I see no reason why it shouldn't also be able to work like `function::assign`.

Can you elaborate?

There draft should individually specify those functions. The new assign/allocate_assign performs

unique_function( allocator_arg_t, a, any_piecewise_construct_tag<F>, std::forward<Args>(args)... ).swap(*this);

(This is an overspecification, since it requires an extraneous move in the small-function optimization case, but the style is how std::function is currently specified.)

Similarly, `emplace_assign` should simply be called `emplace`. These sound more like the standard

Ehh, but emplace always does an insert operation, not an overwrite operation.

I'm going to assume that you intended to add an `operator()` overload in there somewhere. ;) However, unlike Casey Carter, I would not suggest attempting to fix the thread safety problem until the committee has decided how they're going to fix it in `std::function`. We don't want two completely different fixes involved.

I initially wrote the synopsis including all the member signatures of std::function. That was really messy, so I rewrote it with using declarations. The private-inheritance thing was really distracting and misleading so I just put a one-line comment instead.

I’ll add a second comment line, since I guess a <functional> proposal that never mentions the call operator is weird.

That's not to say that something shouldn't be done. It's more to say that this proposal should hold off on committing to any one solution until more is known.

There’s a separate proposal, which I actually split this one from:

std::function has some rough edges. Its interface is a product of evolution, and not necessarily the expression of a consistent theory. A model is presented to describe what std::function already safely does. Evolutionary, not-immediately-breaking solutions to all the problems presented in N4159 are proposed, plus further extensions.

Specifically, this proposal includes:

• Specializations over cv-qualified and ref-qualified signatures
• Multiple signatures in a single specialization
• Interface unification with std::any from the Library Fundamentals TS
• A functor adapter template critical_section for adding thread safety

So, std::unique_function< void() &, void() const &, void() && > would be a handle to a non-copyable function object which discriminates the major access styles.

Stay tuned. It’s Deusy.

Lastly, bikeshedding. I'm not sure that `unique` is the right word. Oh, it conjures up thoughts of `unique_ptr`, which makes you think "move only". But `unique_ptr` is about ownership of memory, while `unique_function` is just about being a move-only function wrapper. At the same time, I cannot come up with a more explicit name that doesn't sound silly (like `move_only_function`).

It’s not about the memory, it’s about the object in the memory. The ownership idea is the same. There’s the small-function optimization, but it doesn’t really make a conceptual difference. It gets disabled if there’s no move constructor.

move_only_function doesn’t fit because targets may be copyable or non-movable.

David Krauss

unread,
May 19, 2015, 9:27:02 PM5/19/15
to std-pr...@isocpp.org
On 2015–05–20, at 1:49 AM, Nevin Liber <ne...@eviloverlord.com> wrote:

Can't you always make unique_any moveable, given that it can allocate in the heap?

unique_any is not proposed here, only mentioned in “future directions.”

Also, consider making unique_function(unique_function&&) noexcept.

The noexcept qualification of unique_function is the same as for function. Both allow exceptions to propagate from the move constructor when the small function optimization is applied. It’s a rare corner case, but there’s no static information to make any guarantee.

Nevin Liber

unread,
May 19, 2015, 9:41:06 PM5/19/15
to std-pr...@isocpp.org
On 19 May 2015 at 20:26, David Krauss <pot...@gmail.com> wrote:

On 2015–05–20, at 1:49 AM, Nevin Liber <ne...@eviloverlord.com> wrote:

Can't you always make unique_any moveable, given that it can allocate in the heap?

unique_any is not proposed here, only mentioned in “future directions.”

So it's off limits to talk about here?
Also, consider making unique_function(unique_function&&) noexcept.

The noexcept qualification of unique_function is the same as for function. Both allow exceptions to propagate from the move constructor when the small function optimization is applied. It’s a rare corner case, but there’s no static information to make any guarantee.

Fine.  Should you present this in Kona, I'll bring this up in LEWG.  As we like to say, until you present a proposal, it's your time to waste.

David Krauss

unread,
May 19, 2015, 9:53:52 PM5/19/15
to std-pr...@isocpp.org
That’s an idea. I don’t know if it’s worth it, but I’ll add it as a note.

The idea would apply to std::function just as well.

The main problem is that most explicitly-defined move constructors in practice aren’t noexcept, just because people forget. On the other hand, most classes with an explicitly-defined move constructor (or composed from something with one) are big enough that the in-wrapper storage optimization won’t apply anyway.

Also, another corner case: the move constructor will allocate memory when the source has a non-POCMA (allocator_traits::propagate_on_container_move_assignment) allocator. I’m not really seeing an exception-safety guarantee being feasible.

Nevin Liber

unread,
May 19, 2015, 10:19:25 PM5/19/15
to std-pr...@isocpp.org
On 19 May 2015 at 20:53, David Krauss <pot...@gmail.com> wrote:
Also, another corner case: the move constructor will allocate memory when the source has a non-POCMA (allocator_traits::propagate_on_container_move_assignment) allocator. I’m not really seeing an exception-safety guarantee being feasible.

std::vector and std::basic_string have noexcept(true) move constructors.  Are you saying they can't use propagate_on_container_move_assignment allocators?
-- 

David Krauss

unread,
May 19, 2015, 10:27:28 PM5/19/15
to std-pr...@isocpp.org
On 2015–05–20, at 9:40 AM, Nevin Liber <ne...@eviloverlord.com> wrote:

The noexcept qualification of unique_function is the same as for function. Both allow exceptions to propagate from the move constructor when the small function optimization is applied. It’s a rare corner case, but there’s no static information to make any guarantee.

Fine.  Should you present this in Kona, I'll bring this up in LEWG.  As we like to say, until you present a proposal, it's your time to waste.

I don’t understand.

So far, I think noexcept-movable std::function deserves its own paper. Now I’m leaning towards saying that it is feasible, but:

1. A throwing move constructor should force heap allocation (disable memory optimization). Essentially, both std::function and std::unique_function would treat a throwing move constructor as if it didn’t exist, even while the former may use the copy constructor.

2. std::function is inherently POCMA, and passing a non-POCMA allocator should be ill-formed.


On 2015–05–20, at 10:18 AM, Nevin Liber <ne...@eviloverlord.com> wrote:

std::vector and std::basic_string have noexcept(true) move constructors.  Are you saying they can't use propagate_on_container_move_assignment allocators?

Not quite, their noexcept specifications depend on the POCMA of the allocator template parameter.

The idea behind POCMA (or lack thereof) is that you can keep an allocator attached to a container. But it’s not really designed to work with polymorphism, which introduces the condition where the current allocator is non-POCMA and the RHS of assignment, being POCMA, wants to replace it. If function were to respect the literal meaning, any would-be attached allocator is at the mercy of every assignment operation. So, I conclude point #2 above.

(Also, non-POCMA would be a major pain to implement.)

David Krauss

unread,
May 19, 2015, 10:39:55 PM5/19/15
to std-pr...@isocpp.org

On 2015–05–20, at 10:27 AM, David Krauss <pot...@mac.com> wrote:

So far, I think noexcept-movable std::function deserves its own paper.

Nah, really it amounts to two separate defects. I’ll report the POCMA thing, since it’s almost just academic, and you can take care of throwing move constructors if you like.

Arthur O'Dwyer

unread,
Jun 25, 2015, 3:03:09 AM6/25/15
to std-pr...@isocpp.org, David Krauss
On Tuesday, May 19, 2015 at 10:48:25 AM UTC-7, Matt Calabrese wrote:
On Tue, May 19, 2015 at 10:26 AM, Casey Carter <cart...@gmail.com> wrote:

On Tuesday, May 19, 2015 at 11:07:03 AM UTC-5, David Krauss wrote:
Here’s a first draft of a non-copyable polymorphic call wrapper proposal: http://bit.ly/uniqfun

unique_function would probably be more useful if it had operator(). Joking aside, there should probably be three overloads qualified by &, const&, and && respectively. That way you both avoid std::function's threadsafety problems (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4348.html) and enable unique_function to usefully hold "one-shot" functions.

Please no, as this would require type erasing all of those. I've been working on a similar effort and my personal thoughts are that the qualification should be specified as a part of the function type, with exactly one signature being erased (and that signature being reflected at the top-level as well):

unique_function<void() const> // for operator() const
unique_function<void() &&> // for operator() &&

This is exactly N4159 "std::function and beyond", correct?

N4159 strikes me as exactly the reasonable and sensible thing to do (both to fix the thread-safety/const-correctness issue, and to enable std::function-izing of move-only lambdas); can anyone shed some light on its current disposition?

David Krauss, as the author of N4543 (std::unique_function<R(A...)>), do you think it's in any way preferable to N4159 (std::function<R(A...)&&>), as in,
- is there a good reason to reject N4159?
- if N4159 were adopted, would there still be a good reason to adopt N4543?
I would understand the argument "N4159 is preferable, but N4543 is a decent consolation prize were N4159 to be rejected"; I'm just wondering whether that's the only motivating argument behind N4543 or whether I'm missing something.

–Arthur

P.S.: I just ran into this issue while attempting to write a Scheduler that manipulates Tasks, where a Task might be for example a lambda one of whose captures is a non-copyable UniquePromise. My solution was to implement Task from scratch; but in a perfect world Task would have been a typedef for std::function<void()&&>.

David Krauss

unread,
Jun 25, 2015, 3:37:03 AM6/25/15
to Arthur O'Dwyer, std-pr...@isocpp.org
On 2015–06–25, at 3:03 PM, Arthur O'Dwyer <arthur....@gmail.com> wrote:

This is exactly N4159 "std::function and beyond", correct?

Not “exactly,” but pretty much.

N4159 strikes me as exactly the reasonable and sensible thing to do (both to fix the thread-safety/const-correctness issue, and to enable std::function-izing of move-only lambdas); can anyone shed some light on its current disposition?

N4159 was accepted as a good to-do list. N4348 and N4543 are follow-ups.

David Krauss, as the author of N4543 (std::unique_function<R(A...)>), do you think it's in any way preferable to N4159 (std::function<R(A...)&&>), as in,
- is there a good reason to reject N4159?
- if N4159 were adopted, would there still be a good reason to adopt N4543?

Some cognitive dissonance here. How have I contradicted N4159?

If you want to allow non-copyable targets, there are only two choices: 1. Let std::function accept them and define its copy constructor to throw (or UB), or 2. Create a new, non-copyable polymorphic wrapper.

Looking at page 8 of N4159, it suggests the name std::movable_function for what I called unique_function. It goes on to suggest a combined template std::basic_function with a bool non-type parameter. I left this as an implementation detail; I don’t think it’s a good interface. I don’t see it analyzing alternative #1 at all.

P.S.: I just ran into this issue while attempting to write a Scheduler that manipulates Tasks, where a Task might be for example a lambda one of whose captures is a non-copyable UniquePromise. My solution was to implement Task from scratch; but in a perfect world Task would have been a typedef for std::function<void()&&>.

That would be std::unique_function<void()>. Put an rvalue qualifier inside if you like. See this summary from the documentation to my prototype library.

LEWG in Urbana took a number of straw polls to refine the direction of N4159. They’re in the LEWG bugzilla but I can’t find the link right now.

David Krauss

unread,
Jun 25, 2015, 3:51:06 AM6/25/15
to Arthur O'Dwyer, std-pr...@isocpp.org
On 2015–06–25, at 3:03 PM, Arthur O'Dwyer <arthur....@gmail.com> wrote:

David Krauss, as the author of N4543 (std::unique_function<R(A...)>), do you think it's in any way preferable to N4159 (std::function<R(A...)&&>), as in,

I see the confusion now. These are orthogonal problems:

1. Can no more than one copy of the target exist? (Solution: unique_function.) 
2. Can a given copy be called not more than once? (Solution: function<R(A...)&&>.)

N4159 already explains this distinction, but the exposition might not be clear enough.

More depth is provided by the link at the end of the previous message. Most of the time, rvalue ref-qualification is going to be a bit obscure (as it always has been), and unique_function is what you’ll be looking for.

Arthur O'Dwyer

unread,
Jun 25, 2015, 3:53:01 AM6/25/15
to std-pr...@isocpp.org, David Krauss
On Thu, Jun 25, 2015 at 12:36 AM, David Krauss <david...@me.com> wrote:
> On 2015–06–25, at 3:03 PM, Arthur O'Dwyer <arthur....@gmail.com> wrote:
>>
>> N4159 strikes me as exactly the reasonable and sensible thing to do (both to
>> fix the thread-safety/const-correctness issue, and to enable
>> std::function-izing of move-only lambdas); can anyone shed some light on its
>> current disposition?
>
> N4159 was accepted as a good to-do list. N4348 and N4543 are follow-ups.
>
>> David Krauss, as the author of N4543 (std::unique_function<R(A...)>), do you
>> think it's in any way preferable to N4159 (std::function<R(A...)&&>), as in,
>> - is there a good reason to reject N4159?
>> - if N4159 were adopted, would there still be a good reason to adopt N4543?
>
> Some cognitive dissonance here. How have I contradicted N4159?

Aha, you merely contradicted my misreading of N4159! Basically, I
misinterpreted the && qualifier on N4159's std::function<R(A...)&&> as
meaning "move-only", when really N4159 intends it to be read literally
as "calling operator()&& on the wrapped object" and not saying
anything about the copyability of the wrapped object.

Page 11 of N4159 even says "Of course, we cannot specify copyability
in such a way, so we still need a parameter for that (or, perhaps, two
separate templates)." I just completely skipped over that in my
misreading. :P

> If you want to allow non-copyable targets, there are only two choices: 1.
> Let std::function accept them and define its copy constructor to throw (or
> UB), or 2. Create a new, non-copyable polymorphic wrapper.

Or #3 (my misreading) assume that nobody would ever want to literally
"call operator()&& on the wrapped object" and therefore it's safe to
co-opt that qualifier to mean "move-only".

Your prototype library's documentation covers this misconception in
one sentence:
> Note that copyability is different from an rvalue-qualified (&&) signature.
True dat.

Thanks for the reply and for the info on N4159/N4348/N4543's current
disposition,
–Arthur
Reply all
Reply to author
Forward
0 new messages