Is it illegal to invoke a std::function unde

2019-01-11 10:04发布

问题:

All quotes are from N3797.

4/3 [conv]

An expression e can be implicitly converted to a type T if and only if the declaration T t=e; is well-formed, for some invented temporary variable t

This implies no expression can be implicitly converted to void, as void t=e is illegal for all expressions e. This is even true if e is an expression of type void, such as void(3).

So an expression of type void cannot be implicitly converted to void.

Which leads us to:

20.9.2/2 Requirements [func.require]

Define INVOKE (f, t1, t2, ..., tN, R) as INVOKE (f, t1, t2, ..., tN) implicitly converted to R .

In short, INVOKE(f, t1, t2, ..., tN, R) is never valid when R is void, as nothing (including void) can be implicitly converted to void.

As a result of this, all std::function<void(Args...)> have the property !*this and thus cannot be called, as the only constructors that do not have !*this as a postcondition (or do not copy such state from another function of the same type) require Callable of one of the parameters.

20.9.11.2/7 Class template function [func.wrap.func]

Requires: F shall be CopyConstructible . f shall be Callable ( 20.9.11.2 ) for argument types ArgTypes and return type R . The copy constructor and destructor of A shall not throw exceptions.

20.9.11.2/2 Class template function [func.wrap.func]

A callable object f of type F is Callable for argument types ArgTypes and return type R if the expres- sion INVOKE (f, declval()..., R) , considered as an unevaluated operand (Clause 5 ), is well formed ( 20.9.2 ).

As demonstrated above, there are no Callable expressions for std::function<void(Args...)>.

If somehow such a std::function<void(Args...)> where found, invoking operator() would be ill formed:

invocation [func.wrap.func.inv]

Effects: INVOKE (f, std::forward(args)..., R) ( 20.9.2 ), where f is the target ob- ject ( 20.9.1 ) of *this .

as INVOKE(f, std::forward<ArgTypes>(args)..., void) is ill formed for all arguments and f.

Is this line of reasoning sound?

回答1:

Yes, your analysis is correct; I came to the same conclusion here.

According to Daniel Kruegler, this issue should appear on the library defect list subsequent to the next mailing:

A corresponding library issue has already been submitted, but is not yet visible in the issue list.

Hopefully once that becomes visible we'll also have a conclusive answer to whether it is allowable to construct a std::function with signature returning void passing a callable with signature returning non-void (Using `std::function<void(...)>` to call non-void function).


Update: this was entered as LWG 2420, which was resolved in favor of special-casing void return type to static_cast the result of the invoked function to void. This means that a callable returning non-void can be the target of a std::function<void(...)>. LWG2420 was applied as a post-publication correction to C++14; meanwhile, all compilers I'm aware of effectively apply this behavior as an extension in C++11 mode.