[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 <ldionne.2@gmail.com>
This commit is contained in:
Igor Zhukov 2023-09-19 16:51:25 -04:00 committed by Louis Dionne
parent 923285b139
commit 910b76a002
3 changed files with 78 additions and 5 deletions

View File

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

Can't render this file because it has a wrong number of fields in line 2.

View File

@ -240,7 +240,8 @@ template <class _Fp,
class _DecayA0 = __decay_t<_A0>,
class _ClassT = typename __member_pointer_class_type<_DecayFp>::type>
using __enable_if_bullet1 =
__enable_if_t<is_member_function_pointer<_DecayFp>::value && is_base_of<_ClassT, _DecayA0>::value>;
__enable_if_t<is_member_function_pointer<_DecayFp>::value &&
(is_same<_ClassT, _DecayA0>::value || is_base_of<_ClassT, _DecayA0>::value)>;
template <class _Fp, class _A0, class _DecayFp = __decay_t<_Fp>, class _DecayA0 = __decay_t<_A0> >
using __enable_if_bullet2 =
@ -252,7 +253,8 @@ template <class _Fp,
class _DecayA0 = __decay_t<_A0>,
class _ClassT = typename __member_pointer_class_type<_DecayFp>::type>
using __enable_if_bullet3 =
__enable_if_t<is_member_function_pointer<_DecayFp>::value && !is_base_of<_ClassT, _DecayA0>::value &&
__enable_if_t<is_member_function_pointer<_DecayFp>::value &&
!(is_same<_ClassT, _DecayA0>::value || is_base_of<_ClassT, _DecayA0>::value) &&
!__is_reference_wrapper<_DecayA0>::value>;
template <class _Fp,
@ -261,7 +263,8 @@ template <class _Fp,
class _DecayA0 = __decay_t<_A0>,
class _ClassT = typename __member_pointer_class_type<_DecayFp>::type>
using __enable_if_bullet4 =
__enable_if_t<is_member_object_pointer<_DecayFp>::value && is_base_of<_ClassT, _DecayA0>::value>;
__enable_if_t<is_member_object_pointer<_DecayFp>::value &&
(is_same<_ClassT, _DecayA0>::value || is_base_of<_ClassT, _DecayA0>::value)>;
template <class _Fp, class _A0, class _DecayFp = __decay_t<_Fp>, class _DecayA0 = __decay_t<_A0> >
using __enable_if_bullet5 =
@ -273,7 +276,8 @@ template <class _Fp,
class _DecayA0 = __decay_t<_A0>,
class _ClassT = typename __member_pointer_class_type<_DecayFp>::type>
using __enable_if_bullet6 =
__enable_if_t<is_member_object_pointer<_DecayFp>::value && !is_base_of<_ClassT, _DecayA0>::value &&
__enable_if_t<is_member_object_pointer<_DecayFp>::value &&
!(is_same<_ClassT, _DecayA0>::value || is_base_of<_ClassT, _DecayA0>::value) &&
!__is_reference_wrapper<_DecayA0>::value>;
// __invoke forward declarations

View File

@ -346,6 +346,75 @@ void noexcept_test() {
}
}
// LWG3655: The INVOKE operation and union types
void union_tests() {
union Union {
int x;
int f() { return 42; }
int g() const { return 52; }
};
// With a data member
{
auto get = []() -> Union { return Union{.x = 3}; };
int result = std::invoke(&Union::x, get());
assert(result == 3);
}
{
auto get = []() -> Union const { return Union{.x = 3}; };
int result = std::invoke(&Union::x, get());
assert(result == 3);
}
{
Union u{3};
int& result = std::invoke(&Union::x, u);
assert(&result == &u.x);
}
{
Union const u{3};
int const& result = std::invoke(&Union::x, u);
assert(&result == &u.x);
}
// With a pointer to a member function
{
auto get = []() -> Union { return Union{.x = 3}; };
int result = std::invoke(&Union::f, get());
assert(result == 42);
}
{
Union u{3};
int result = std::invoke(&Union::f, u);
assert(result == 42);
}
{
// constness mismatch
static_assert(!std::is_invocable_v<int (Union::*)(), Union const>);
static_assert(!std::is_invocable_v<int (Union::*)(), Union const&>);
}
{
auto get = []() -> Union { return Union{.x = 3}; };
int result = std::invoke(&Union::g, get());
assert(result == 52);
}
{
auto get = []() -> Union const { return Union{.x = 3}; };
int result = std::invoke(&Union::g, get());
assert(result == 52);
}
{
Union u{3};
int result = std::invoke(&Union::g, u);
assert(result == 52);
}
{
Union const u{3};
int result = std::invoke(&Union::g, u);
assert(result == 52);
}
}
int main(int, char**) {
bullet_one_two_tests();
bullet_three_four_tests();