This page is a snapshot from the LWG issues list, see theLibrary Active Issues List for more information and the meaning ofC++23 status.
INVOKE operation andunion typesSection: 22.10.4[func.require]Status:C++23Submitter: Jiang AnOpened: 2021-12-29Last modified: 2023-11-22
Priority:3
View otheractive issues in [func.require].
View all otherissues in [func.require].
View all issues withC++23 status.
Discussion:
There are two cases of theINVOKE operation specified withstd::is_base_of_v (22.10.4[func.require] (1.1), (1,4)), which means the following code snippet is ill-formed, asstd::is_base_of_v<B, D> isfalse when eitherB orD is aunion 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 handleunion types. libc++ and MSVC STL reject this code as specified in 22.10.4[func.require].
union types?[2022-01-30; Reflector poll]
Set priority to 3 after reflector poll.
[2023-02-07; Jonathan adds wording]
This is a regression introduced by LWG2219(i).In C++14std::result_of<int Foo::*(Foo&)>::typewas valid, because theINVOKE wording used to say"f is a pointer to member data of a classTandt1 is an object of typeTor a reference to an object of typeTor a reference to an object of a type derived fromT".Since LWG 2219 we useis_base_of which is always false forunion types.I don't think LWG 2219 intended to break this case, so we should fix it.
Previous resolution [SUPERSEDED]:
This wording is relative toN4928.
Modify 22.10.4[func.require] as indicated:
-1-Define
INVOKE(f, t1, t2, …, tN)as follows:
- (1.1) —
(t1.*f)(t2, …, tN)whenfis a pointer to a member function of a classTandis_same_v<T, remove_cvref_t<decltype(t1)>> ||is_base_of_v<T, remove_reference_t<decltype(t1)>>istrue;- (1.2) —
(t1.get().*f)(t2, …, tN)whenfis a pointer to a member function of a classTandremove_cvref_t<decltype(t1)>is a specialization ofreference_wrapper;- (1.3) —
((*t1).*f)(t2, …, tN)whenfis a pointer to a member function of a classTandt1does not satisfy the previous two items;- (1.4) —
t1.*fwhenN == 1andfis a pointer to data member of a classTandis_same_v<T, remove_cvref_t<decltype(t1)>> ||is_base_of_v<T, remove_reference_t<decltype(t1)>>istrue;- (1.5) —
t1.get().*fwhenN == 1andfis a pointer to data member of a classTandremove_cvref_t<decltype(t1)>is a specialization ofreference_wrapper;- (1.6) —
(*t1).*fwhenN == 1andfis a pointer to data member of a classTandt1does not satisfy the previous two items;- (1.7) —
f(t1, t2, …, tN)in all other cases.
[2023-02-07; Jonathan provides wording change requested by LWG]
Changeremove_reference_t toremove_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.
[Issaquah 2023-02-07; LWG]
Move to Immediate for C++23
[2023-02-13 Approved at February 2023 meeting in Issaquah. Status changed: Immediate → WP.]
Proposed resolution:
This wording is relative toN4928.
Modify 22.10.4[func.require] as indicated:
-1-Define
INVOKE(f, t1, t2, …, tN)as follows:
- (1.1) —
(t1.*f)(t2, …, tN)whenfis a pointer to a member function of a classTandis_same_v<T, remove_cvref_t<decltype(t1)>> ||is_base_of_v<T, remove_isreferencecvref_t<decltype(t1)>>true;- (1.2) —
(t1.get().*f)(t2, …, tN)whenfis a pointer to a member function of a classTandremove_cvref_t<decltype(t1)>is a specialization ofreference_wrapper;- (1.3) —
((*t1).*f)(t2, …, tN)whenfis a pointer to a member function of a classTandt1does not satisfy the previous two items;- (1.4) —
t1.*fwhenN == 1andfis a pointer to data member of a classTandis_same_v<T, remove_cvref_t<decltype(t1)>> ||is_base_of_v<T, remove_isreferencecvref_t<decltype(t1)>>true;- (1.5) —
t1.get().*fwhenN == 1andfis a pointer to data member of a classTandremove_cvref_t<decltype(t1)>is a specialization ofreference_wrapper;- (1.6) —
(*t1).*fwhenN == 1andfis a pointer to data member of a classTandt1does not satisfy the previous two items;- (1.7) —
f(t1, t2, …, tN)in all other cases.