This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.
Section: 22.10.4 [func.require] Status: WP Submitter: Jiang An Opened: 2021-12-29 Last modified: 2023-02-13
Priority: 3
View all other issues in [func.require].
View all issues with WP status.
Discussion:
There are two cases of the INVOKE operation specified with std::is_base_of_v (22.10.4 [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 22.10.4 [func.require].
Should we change the conditions in 22.10.4 [func.require] (1.1) and (1.4) to match libstdc++ and correctly handle 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 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.
Modify 22.10.4 [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.
[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.
[Issaquah 2023-02-07; LWG]
Move to Immediate for C++23
[2023-02-13 Status changed: Immediate → WP.]
Proposed resolution:
This wording is relative to N4928.
Modify 22.10.4 [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.