This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of Resolved status.

### 2690. `invoke<R>`

Section: 20.14.5 [func.invoke] Status: Resolved Submitter: Zhihao Yuan Opened: 2016-03-25 Last modified: 2021-06-12

Priority: Not Prioritized

View all other issues in [func.invoke].

View all issues with Resolved status.

Discussion:

In N4169 the author dropped the `invoke<R>` support by claiming that it's an unnecessary cruft in TR1, obsoleted by C++11 type inference. But now we have some new business went to *`INVOKE`*`(f, t1, t2, ..., tN, R)`, that is to discard the return type when `R` is `void`. This form is very useful, or possible even more useful than the basic form when implementing a call wrapper. Also note that the optional `R` support is already in `std::is_callable` and `std::is_nothrow_callable`.

[2016-07-31, Tomasz Kamiński comments]

The lack of `invoke<R>` was basically a result of the concurrent publication of the never revision of the paper and additional special semantics of `INVOKE(f, args..., void)`.

In contrast to existing `std::invoke` function, the proposed `invoke<R>` version is not SFINAE friendly, as elimination of the standard version of invoke is guaranteed by `std::result_of_t` in the result type that is missing for proposed `invoke<R>` version. To provide this guarantee, following remarks shall be added to the specification:

> Remarks: This function shall not participate in overload resolution unless `is_callable_v<F(Args...), R>` is `true`.

[2016-08-01, Tomasz Kamiński and Zhihao Yuan update the proposed wording]

Previous resolution [SUPERSEDED]:

> This wording is relative to N4606.

> 1. Modify 20.14 [function.objects]/2, header `<functional>` synopsis, as indicated:

>    >     namespace std {
>    >       // 20.12.3, invoke:
>    >       template <class F, class... Args> result_of_t<F&&(Args&&...)> invoke(F&& f, Args&&... args);
>    >       template <class R, class F, class... Args> R invoke(F&& f, Args&&... args);

> 2. Add the following sequence of paragraphs after 20.14.5 [func.invoke]/1 as indicated:

>    >     template <class R, class F, class... Args> R invoke(F&& f, Args&&... args);

>    > > -?- Returns: `INVOKE(std::forward<F>(f), std::forward<Args>(args)..., R)` (20.14.4 [func.require]).

>    > > -?- Remarks: This function shall not participate in overload resolution unless `is_callable_v<F(Args...), R>` is `true`.

[2016-09-04, Tomasz Kamiński comments and improves wording]

The usage of `is_callable_v<F(Args...), R>` causes problem in situation when either `F` or `Args` is an abstract type and the function type `F(Args...)` cannot be formed or when one of the args is cv-qualified, as top-level cv-qualification for function parameters is dropped by language rules. It should use `is_callable_v<F&&(Args&&...), R>` instead.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4606.

> 1. Modify 20.14 [function.objects]/2, header `<functional>` synopsis, as indicated:

>    >     namespace std {
>    >       // 20.12.3, invoke:
>    >       template <class F, class... Args> result_of_t<F&&(Args&&...)> invoke(F&& f, Args&&... args);
>    >       template <class R, class F, class... Args> R invoke(F&& f, Args&&... args);

> 2. Add the following sequence of paragraphs after 20.14.5 [func.invoke]/1 as indicated:

>    >     template <class R, class F, class... Args> R invoke(F&& f, Args&&... args);

>    > > -?- Returns: `INVOKE(std::forward<F>(f), std::forward<Args>(args)..., R)` (20.14.4 [func.require]).

>    > > -?- Remarks: This function shall not participate in overload resolution unless `is_callable_v<F&&(Args&&...), R>` is `true`.

[2018-08-22, Zhihao Yuan provides improved wording]

Previous resolution [SUPERSEDED]:

> This wording is relative to N4762.

> 1. Modify 20.14.2 [functional.syn], header `<functional>` synopsis, as indicated:

>    >     namespace std {
>    >       // 20.14.5 [func.invoke], invoke
>    >       template<class F, class... Args>
>    >         invoke_result_t<F, Args...> invoke(F&& f, Args&&... args)
>    >           noexcept(is_nothrow_invocable_v<F, Args...>);
>    >       template <class R, class F, class... Args>
>    >         R invoke(F&& f, Args&&... args)
>    >           noexcept(is_nothrow_invocable_r_v<R, F, Args...>);

> 2. Add the following sequence of paragraphs after 20.14.5 [func.invoke]/1 as indicated:

>    >     template <class R, class F, class... Args>
>    >       R invoke(F&& f, Args&&... args)
>    >         noexcept(is_nothrow_invocable_r_v<R, F, Args...>);

>    > > -?- Constraints: `is_invocable_r_v<R, F, Args...>`.

>    > > -?- Returns: `INVOKE<R>(std::forward<F>(f), std::forward<Args>(args)...)` (20.14.4 [func.require]).

[2021-06-12; Resolved by accepting P2136R3.]

Proposed resolution:

This wording is relative to N4849.

1. Modify 20.14.2 [functional.syn], header `<functional>` synopsis, as indicated:

   >     namespace std {
   >       // 20.14.5 [func.invoke], invoke
   >       template<class F, class... Args>
   >         constexpr invoke_result_t<F, Args...> invoke(F&& f, Args&&... args)
   >           noexcept(is_nothrow_invocable_v<F, Args...>);
   >       template <class R, class F, class... Args>
   >         constexpr R invoke(F&& f, Args&&... args)
   >           noexcept(is_nothrow_invocable_r_v<R, F, Args...>);

2. Add the following sequence of paragraphs after 20.14.5 [func.invoke]/1 as indicated:

   >     template <class R, class F, class... Args>
   >       constexpr R invoke(F&& f, Args&&... args)
   >         noexcept(is_nothrow_invocable_r_v<R, F, Args...>);

   > > -?- Constraints: `is_invocable_r_v<R, F, Args...>`.

   > > -?- Returns: `INVOKE<R>(std::forward<F>(f), std::forward<Args>(args)...)` (20.14.4 [func.require]).