Title
The INVOKE operation and union types
Status
c++23
Section
[func.require]
Submitter
Jiang An

Created on 2021-12-29.00:00:00 last changed 4 months ago

Messages

Date: 2023-02-13.11:31:32

Proposed resolution:

This wording is relative to N4928.

  1. Modify [func.require] as indicated:

    -1- Define INVOKE(f, t1, t2, …, tN) as follows:

    • (1.1) — (t1.*f)(t2, …, tN) when f is a pointer to a member function of a class T and is_same_v<T, remove_cvref_t<decltype(t1)>> || is_base_of_v<T, remove_referencecvref_t<decltype(t1)>> is true;
    • (1.2) — (t1.get().*f)(t2, …, tN) when f is a pointer to a member function of a class T and remove_cvref_t<decltype(t1)> is a specialization of reference_wrapper;
    • (1.3) — ((*t1).*f)(t2, …, tN) when f is a pointer to a member function of a class T and t1 does not satisfy the previous two items;
    • (1.4) — t1.*f when N == 1 and f is a pointer to data member of a class T and is_same_v<T, remove_cvref_t<decltype(t1)>> || is_base_of_v<T, remove_referencecvref_t<decltype(t1)>> is true;
    • (1.5) — t1.get().*f when N == 1 and f is a pointer to data member of a class T and remove_cvref_t<decltype(t1)> is a specialization of reference_wrapper;
    • (1.6) — (*t1).*f when N == 1 and f is a pointer to data member of a class T and t1 does not satisfy the previous two items;
    • (1.7) — f(t1, t2, …, tN) in all other cases.
Date: 2023-02-13.00:00:00

[ 2023-02-13 Approved at February 2023 meeting in Issaquah. Status changed: Immediate → WP. ]

Date: 2023-02-07.18:07:56

[ Issaquah 2023-02-07; LWG ]

Move to Immediate for C++23

Date: 2023-02-15.00:00:00

[ 2023-02-07; Jonathan provides wording change requested by LWG ]

Change remove_reference_t to remove_cvref_t. is_base_of ignores cv-qualifiers, so this isn't necessary, but just using the same transformation in both cases seems simpler to grok.

Date: 2023-02-15.00:00:00

[ 2023-02-07; Jonathan adds wording ]

This is a regression introduced by LWG 2219. In C++14 std::result_of<int Foo::*(Foo&)>::type was valid, because the INVOKE wording used to say "f is a pointer to member data of a class T and t1 is an object of type T or a reference to an object of type T or a reference to an object of a type derived from T". Since LWG 2219 we use is_base_of which is always false for union types. I don't think LWG 2219 intended to break this case, so we should fix it.

Previous resolution [SUPERSEDED]:

This wording is relative to N4928.

  1. Modify [func.require] as indicated:

    -1- Define INVOKE(f, t1, t2, …, tN) as follows:

    • (1.1) — (t1.*f)(t2, …, tN) when f is a pointer to a member function of a class T and is_same_v<T, remove_cvref_t<decltype(t1)>> || is_base_of_v<T, remove_reference_t<decltype(t1)>> is true;
    • (1.2) — (t1.get().*f)(t2, …, tN) when f is a pointer to a member function of a class T and remove_cvref_t<decltype(t1)> is a specialization of reference_wrapper;
    • (1.3) — ((*t1).*f)(t2, …, tN) when f is a pointer to a member function of a class T and t1 does not satisfy the previous two items;
    • (1.4) — t1.*f when N == 1 and f is a pointer to data member of a class T and is_same_v<T, remove_cvref_t<decltype(t1)>> || is_base_of_v<T, remove_reference_t<decltype(t1)>> is true;
    • (1.5) — t1.get().*f when N == 1 and f is a pointer to data member of a class T and remove_cvref_t<decltype(t1)> is a specialization of reference_wrapper;
    • (1.6) — (*t1).*f when N == 1 and f is a pointer to data member of a class T and t1 does not satisfy the previous two items;
    • (1.7) — f(t1, t2, …, tN) in all other cases.
Date: 2022-01-15.00:00:00

[ 2022-01-30; Reflector poll ]

Set priority to 3 after reflector poll.

Date: 2021-12-29.00:00:00

There are two cases of the INVOKE operation specified with std::is_base_of_v ([func.require] (1.1), (1,4)), which means the following code snippet is ill-formed, as std::is_base_of_v<B, D> is false when either B or D is a union type.

union Foo { int x; };
static_assert(std::is_invocable_v<int Foo::*, Foo&>);

Currently libstdc++ accepts this code, because it uses slightly different conditions that handle union types. libc++ and MSVC STL reject this code as specified in [func.require].

Should we change the conditions in [func.require] (1.1) and (1.4) to match libstdc++ and correctly handle union types?

History
Date User Action Args
2023-11-22 15:47:43adminsetstatus: wp -> c++23
2023-02-13 11:31:32adminsetmessages: + msg13381
2023-02-13 11:31:32adminsetstatus: immediate -> wp
2023-02-07 18:07:56adminsetmessages: + msg13286
2023-02-07 18:07:56adminsetmessages: + msg13285
2023-02-07 18:07:56adminsetstatus: new -> immediate
2023-02-07 15:05:44adminsetmessages: + msg13284
2023-02-07 15:05:44adminsetmessages: + msg13283
2022-01-30 17:05:36adminsetmessages: + msg12326
2021-12-29 00:00:00admincreate