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 55It 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.
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; […]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>(),
is well formed when treated
declval<ArgTypes>()...,)
R
as an unevaluated operandFn
,and all types in theR
,
parameter packArgTypes
shall
be complete types, cvvoid
, or
arrays of unknown bound.template <class R, class Fn, class...
ArgTypes>
struct is_invocable_r;The expression
INVOKE(declval<Fn>(),
is well formed when treated
declval<ArgTypes>()...,
R)
as an unevaluated operandFn
,R
, and all types in the
parameter packArgTypes
shall
be complete types, cvvoid
, or
arrays of unknown bound.template <class Fn, class...
ArgTypes, class R>
struct is_nothrow_invocablecallable<;
Fn(ArgTypes...), R>is_invocable
iscallable_v<
Fn, ArgTypes...Fn(ArgTypes...), R>
true
and the expression
INVOKE(declval<Fn>(),
is known not to throw any
declval<ArgTypes>()...,)
R
exceptionsFn
,and all types in theR
,
parameter packArgTypes
shall
be complete types, cvvoid
, or
arrays of unknown bound.template <class R, class Fn, class...
ArgTypes, class R>
struct is_nothrow_invocable_r;is_invocable_r_v<
is
R, Fn, ArgTypes...>
true
and the expression
INVOKE(declval<Fn>(),
is known not to throw any
declval<ArgTypes>()...,
R)
exceptionsFn
,R
, and all types in the
parameter packArgTypes
shall
be complete types, cvvoid
, 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: