Skip to content

Commit 910b76a

Browse files
fsb4000ldionne
andcommitted
[libc++] Implement LWG-3655: The INVOKE operation and union types
https://cplusplus.github.io/LWG/issue3655 Differential Revision: https://reviews.llvm.org/D144645 Co-authored-by: Louis Dionne <[email protected]>
1 parent 923285b commit 910b76a

File tree

3 files changed

+78
-5
lines changed

3 files changed

+78
-5
lines changed

libcxx/docs/Status/Cxx23Issues.csv

+1-1
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@
280280
"`3622 <https://wg21.link/LWG3622>`__","Misspecified transitivity of equivalence in §[unord.req.general]","February 2023","","",""
281281
"`3631 <https://wg21.link/LWG3631>`__","``basic_format_arg(T&&)`` should use ``remove_cvref_t<T>`` throughout","February 2023","|Complete|","17.0",""
282282
"`3645 <https://wg21.link/LWG3645>`__","``resize_and_overwrite`` is overspecified to call its callback with lvalues","February 2023","|Complete|","14.0",""
283-
"`3655 <https://wg21.link/LWG3655>`__","The ``INVOKE`` operation and union types","February 2023","","",""
283+
"`3655 <https://wg21.link/LWG3655>`__","The ``INVOKE`` operation and union types","February 2023","|Complete|","18.0",""
284284
"`3723 <https://wg21.link/LWG3723>`__","``priority_queue::push_range`` needs to ``append_range``","February 2023","","","|ranges|"
285285
"`3734 <https://wg21.link/LWG3734>`__","Inconsistency in ``inout_ptr`` and ``out_ptr`` for empty case","February 2023","","",""
286286
"`3772 <https://wg21.link/LWG3772>`__","``repeat_view``'s ``piecewise`` constructor is missing Postconditions","February 2023","","","|ranges|"

libcxx/include/__type_traits/invoke.h

+8-4
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,8 @@ template <class _Fp,
240240
class _DecayA0 = __decay_t<_A0>,
241241
class _ClassT = typename __member_pointer_class_type<_DecayFp>::type>
242242
using __enable_if_bullet1 =
243-
__enable_if_t<is_member_function_pointer<_DecayFp>::value && is_base_of<_ClassT, _DecayA0>::value>;
243+
__enable_if_t<is_member_function_pointer<_DecayFp>::value &&
244+
(is_same<_ClassT, _DecayA0>::value || is_base_of<_ClassT, _DecayA0>::value)>;
244245

245246
template <class _Fp, class _A0, class _DecayFp = __decay_t<_Fp>, class _DecayA0 = __decay_t<_A0> >
246247
using __enable_if_bullet2 =
@@ -252,7 +253,8 @@ template <class _Fp,
252253
class _DecayA0 = __decay_t<_A0>,
253254
class _ClassT = typename __member_pointer_class_type<_DecayFp>::type>
254255
using __enable_if_bullet3 =
255-
__enable_if_t<is_member_function_pointer<_DecayFp>::value && !is_base_of<_ClassT, _DecayA0>::value &&
256+
__enable_if_t<is_member_function_pointer<_DecayFp>::value &&
257+
!(is_same<_ClassT, _DecayA0>::value || is_base_of<_ClassT, _DecayA0>::value) &&
256258
!__is_reference_wrapper<_DecayA0>::value>;
257259

258260
template <class _Fp,
@@ -261,7 +263,8 @@ template <class _Fp,
261263
class _DecayA0 = __decay_t<_A0>,
262264
class _ClassT = typename __member_pointer_class_type<_DecayFp>::type>
263265
using __enable_if_bullet4 =
264-
__enable_if_t<is_member_object_pointer<_DecayFp>::value && is_base_of<_ClassT, _DecayA0>::value>;
266+
__enable_if_t<is_member_object_pointer<_DecayFp>::value &&
267+
(is_same<_ClassT, _DecayA0>::value || is_base_of<_ClassT, _DecayA0>::value)>;
265268

266269
template <class _Fp, class _A0, class _DecayFp = __decay_t<_Fp>, class _DecayA0 = __decay_t<_A0> >
267270
using __enable_if_bullet5 =
@@ -273,7 +276,8 @@ template <class _Fp,
273276
class _DecayA0 = __decay_t<_A0>,
274277
class _ClassT = typename __member_pointer_class_type<_DecayFp>::type>
275278
using __enable_if_bullet6 =
276-
__enable_if_t<is_member_object_pointer<_DecayFp>::value && !is_base_of<_ClassT, _DecayA0>::value &&
279+
__enable_if_t<is_member_object_pointer<_DecayFp>::value &&
280+
!(is_same<_ClassT, _DecayA0>::value || is_base_of<_ClassT, _DecayA0>::value) &&
277281
!__is_reference_wrapper<_DecayA0>::value>;
278282

279283
// __invoke forward declarations

libcxx/test/std/utilities/function.objects/func.invoke/invoke.pass.cpp

+69
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,75 @@ void noexcept_test() {
346346
}
347347
}
348348

349+
// LWG3655: The INVOKE operation and union types
350+
void union_tests() {
351+
union Union {
352+
int x;
353+
int f() { return 42; }
354+
int g() const { return 52; }
355+
};
356+
357+
// With a data member
358+
{
359+
auto get = []() -> Union { return Union{.x = 3}; };
360+
int result = std::invoke(&Union::x, get());
361+
assert(result == 3);
362+
}
363+
{
364+
auto get = []() -> Union const { return Union{.x = 3}; };
365+
int result = std::invoke(&Union::x, get());
366+
assert(result == 3);
367+
}
368+
{
369+
Union u{3};
370+
int& result = std::invoke(&Union::x, u);
371+
assert(&result == &u.x);
372+
}
373+
{
374+
Union const u{3};
375+
int const& result = std::invoke(&Union::x, u);
376+
assert(&result == &u.x);
377+
}
378+
379+
// With a pointer to a member function
380+
{
381+
auto get = []() -> Union { return Union{.x = 3}; };
382+
int result = std::invoke(&Union::f, get());
383+
assert(result == 42);
384+
}
385+
{
386+
Union u{3};
387+
int result = std::invoke(&Union::f, u);
388+
assert(result == 42);
389+
}
390+
{
391+
// constness mismatch
392+
static_assert(!std::is_invocable_v<int (Union::*)(), Union const>);
393+
static_assert(!std::is_invocable_v<int (Union::*)(), Union const&>);
394+
}
395+
396+
{
397+
auto get = []() -> Union { return Union{.x = 3}; };
398+
int result = std::invoke(&Union::g, get());
399+
assert(result == 52);
400+
}
401+
{
402+
auto get = []() -> Union const { return Union{.x = 3}; };
403+
int result = std::invoke(&Union::g, get());
404+
assert(result == 52);
405+
}
406+
{
407+
Union u{3};
408+
int result = std::invoke(&Union::g, u);
409+
assert(result == 52);
410+
}
411+
{
412+
Union const u{3};
413+
int result = std::invoke(&Union::g, u);
414+
assert(result == 52);
415+
}
416+
}
417+
349418
int main(int, char**) {
350419
bullet_one_two_tests();
351420
bullet_three_four_tests();

0 commit comments

Comments
 (0)