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.

### 2895. Passing function types to `result_of` and `is_callable`

Section: 21.3.7 [meta.rel] Status: Resolved Submitter: Great Britain Opened: 2017-02-03 Last modified: 2020-09-06

Priority: Not Prioritized

View other active issues in [meta.rel].

View all other issues in [meta.rel].

View all issues with Resolved status.

Discussion:

Addresses GB 55

It is becoming more and more apparent that using a function type as the template argument to `result_of` causes annoying problems. That was done because C++03 didn't have variadic templates, so it allowed an arbitrary number of types to be smuggled into the template via a single parameter, but it's a hack and unnecessary in C++ today. `result_of<F(Args...)>` has absolutely nothing to do with a function type that returns `F`, and the syntactic trickery using a function type has unfortunate consequences such as top-level cv-qualifiers and arrays decaying (because those are the rules for function types).

It might be too late to change `result_of`, but we should not repeat the same mistake for `std::is_callable`.

Proposed change: Possibly get rid of the `is_callable<Fn(ArgTypes?...), R>` specialization. Change the primary template `is_callable<class, class R = void> to is_callable<class Fn, class.. ArgTypes?>` and define a separate template such as `is_callable_r<class R, class Fn, class... ArgTypes?>` for the version that checks the return type. The resulting inconsistency might need to be resolved/improved upon.

[2017-02, pre-Kona]

See also LWG 2927.

[2017-02-22, Daniel comments and provides concrete wording]

The approach chosen to resolve this issue is a merger with LWG 2928, that is the `callable` traits are also renamed to `invocable`.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4640.

> 1. Modify 21.3.3 [meta.type.synop], header `<type_traits>` synopsis, as indicated:

>    >     […]
>    >     // 20.15.6, type relations
>    >     […]

>    >     template <class, class R = void> struct is_callable; // not defined
>    >     template <class Fn, class... ArgTypes, class R>
>    >     struct is_callable<Fn(ArgTypes...), R>;
>    >     template <class Fn, class... ArgTypes> struct is_invocable;
>    >     template <class R, class Fn, class... ArgTypes> struct is_invocable_r;

>    >     template <class, class R = void> struct is_nothrow_callable; // not defined
>    >     template <class Fn, class... ArgTypes, class R>
>    >     struct is_nothrow_callable<Fn(ArgTypes...), R>;
>    >     template <class Fn, class... ArgTypes> struct is_nothrow_invocable;
>    >     template <class R, class Fn, class... ArgTypes> struct is_nothrow_invocable_r;

>    >     […]

>    >     // 20.15.6, type relations
>    >     […]
>    >     template <class T, class R = void> constexpr bool is_callable_v
>    >     = is_callable<T, R>::value;
>    >     template <class T, class R = void> constexpr bool is_nothrow_callable_v
>    >     = is_nothrow_callable<T, R>::value;
>    >     template <class Fn, class... ArgTypes> constexpr bool is_invocable_v
>    >     = is_invocable<Fn, ArgTypes...>::value;
>    >     template <class R, class Fn, class... ArgTypes> constexpr bool is_invocable_r_v
>    >     = is_invocable_r<R, Fn, ArgTypes...>::value;
>    >     template <class Fn, class... ArgTypes> constexpr bool is_nothrow_invocable_v
>    >     = is_nothrow_invocable<Fn, ArgTypes...>::value;
>    >     template <class R, class Fn, class... ArgTypes> constexpr bool is_nothrow_invocable_r_v
>    >     = is_nothrow_invocable_r<R, Fn, ArgTypes...>::value;
>    >     […]

> 2. Modify 21.3.7 [meta.rel], Table 44 — "Type relationship predicates", as indicated:

>    > Table 44 — Type relationship predicates
>    > `[…]`
>    > `template <class Fn, class... ArgTypes, class R> struct is_invocablecallable< Fn(ArgTypes...), R>;` | The expression `INVOKE(declval<Fn>(), declval<ArgTypes>()..., R)` is well formed when treated as an unevaluated operand | `Fn`, `R`, and all types in the parameter pack `ArgTypes` shall be complete types, cv `void`, or arrays of unknown bound.
>    > `template <class R, class Fn, class... ArgTypes> struct is_invocable_r;` | The expression `INVOKE(declval<Fn>(), declval<ArgTypes>()..., R)` is well formed when treated as an unevaluated operand | `Fn`, `R`, and all types in the parameter pack `ArgTypes` shall be complete types, cv `void`, or arrays of unknown bound.
>    > `template <class Fn, class... ArgTypes, class R> struct is_nothrow_invocablecallable< Fn(ArgTypes...), R>;` | `is_invocablecallable_v< Fn, ArgTypes...Fn(ArgTypes...), R>` is `true` and the expression `INVOKE(declval<Fn>(), declval<ArgTypes>()..., R)` is known not to throw any exceptions | `Fn`, `R`, and all types in the parameter pack `ArgTypes` shall be complete types, cv `void`, or arrays of unknown bound.
>    > `template <class R, class Fn, class... ArgTypes, class R> struct is_nothrow_invocable_r;` | `is_invocable_r_v< R, Fn, ArgTypes...>` is `true` and the expression `INVOKE(declval<Fn>(), declval<ArgTypes>()..., R)` is known not to throw any exceptions | `Fn`, `R`, and all types in the parameter pack `ArgTypes` shall be complete types, cv `void`, or arrays of unknown bound.

[2017-02-24, Daniel comments]

I suggest to apply the paper d0604r0 instead, available on the Kona LWG wiki.

[2017-03-12, post-Kona]

Resolved by p0604r0.

Proposed resolution: