Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement P2445R1 forward_like() #2974

Merged
merged 16 commits into from
Aug 5, 2022
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions stl/inc/__msvc_iter_core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,6 @@ struct random_access_iterator_tag : bidirectional_iterator_tag {};
#ifdef __cpp_lib_concepts
struct contiguous_iterator_tag : random_access_iterator_tag {};

template <class _Ty>
using _With_reference = _Ty&;

template <class _Ty>
concept _Can_reference = requires {
typename _With_reference<_Ty>;
};

template <class _Ty>
concept _Dereferenceable = requires(_Ty& __t) {
{ *__t } -> _Can_reference;
Expand Down
36 changes: 36 additions & 0 deletions stl/inc/utility
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,22 @@ _NODISCARD constexpr bool in_range(const _Ty _Value) noexcept {

return true;
}

#ifdef __cpp_lib_concepts
template <class _Ty>
using _With_reference = _Ty&;

template <class _Ty>
concept _Can_reference = requires {
typename _With_reference<_Ty>;
};
#else
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
template <class _Ty, class = void>
inline constexpr bool _Can_reference = false;

template <class _Ty>
inline constexpr bool _Can_reference<_Ty, void_t<_Ty&>> = true;
#endif // __cpp_lib_concepts
#endif // _HAS_CXX20

#if _HAS_CXX23
Expand All @@ -802,6 +818,26 @@ _NODISCARD constexpr underlying_type_t<_Ty> to_underlying(_Ty _Value) noexcept {
_CSTD abort(); // likely to be called in debug mode, but can't be relied upon - already entered the UB territory
#endif // _DEBUG
}

template <class _Ty, class _Uty>
_NODISCARD constexpr auto&& forward_like(_Uty&& _Ux) noexcept {
static_assert(_Can_reference<_Ty>, "std::forward_like's first template argument must be a referenceable type.");

using _UnrefU = remove_reference_t<_Uty>;
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
if constexpr (is_lvalue_reference_v<_Ty>) {
frederick-vs-ja marked this conversation as resolved.
Show resolved Hide resolved
if constexpr (is_const_v<remove_reference_t<_Ty>>) {
return static_cast<const _UnrefU&>(_Ux);
} else {
return static_cast<_UnrefU&>(_Ux);
}
} else {
if constexpr (is_const_v<remove_reference_t<_Ty>>) {
return static_cast<const _UnrefU&&>(_Ux);
} else {
return static_cast<_UnrefU&&>(_Ux);
}
}
}
#endif // _HAS_CXX23

#if _HAS_TR1_NAMESPACE
Expand Down
2 changes: 2 additions & 0 deletions stl/inc/yvals_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@
// P2441R2 views::join_with
// P2442R1 Windowing Range Adaptors: views::chunk, views::slide
// P2443R1 views::chunk_by
// P2445R1 forward_like()
// P2499R0 string_view Range Constructor Should Be explicit
// P2549R0 unexpected<E>::error()

Expand Down Expand Up @@ -1462,6 +1463,7 @@
#define __cpp_lib_expected 202202L
#endif // __cpp_lib_concepts

#define __cpp_lib_forward_like 202207L
#define __cpp_lib_invoke_r 202106L
#define __cpp_lib_is_scoped_enum 202011L
#define __cpp_lib_move_only_function 202110L
Expand Down
1 change: 1 addition & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,7 @@ tests\P2442R1_views_chunk_death
tests\P2442R1_views_slide
tests\P2443R1_views_chunk_by
tests\P2443R1_views_chunk_by_death
tests\P2445R1_forward_like
tests\VSO_0000000_allocator_propagation
tests\VSO_0000000_any_calling_conventions
tests\VSO_0000000_c_math_functions
Expand Down
4 changes: 4 additions & 0 deletions tests/std/tests/P2445R1_forward_like/env.lst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

RUNALL_INCLUDE ..\usual_latest_matrix.lst
120 changes: 120 additions & 0 deletions tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <type_traits>
#include <utility>

using namespace std;

struct owner_type {
inline static constinit int imut = 0;
static constexpr int iconst = 0;

int m_mutobj = 0;
int& m_mutlref = imut;
int&& m_mutrref = move(imut);

const int m_cobj = 0;
const int& m_clref = iconst;
const int&& m_crref = move(iconst);
};

owner_type owner{};
constexpr owner_type& owner_lref = owner;
constexpr owner_type&& owner_rref = move(owner);

constexpr owner_type owner_c{};
constexpr const owner_type& owner_clref = owner_c;
constexpr const owner_type&& owner_crref = move(owner_c);

using owner_t = decltype(owner);
CaseyCarter marked this conversation as resolved.
Show resolved Hide resolved
using mutobj_from_owner_t = decltype(forward_like<owner_t>(owner.m_mutobj));
using mutlref_from_owner_t = decltype(forward_like<owner_t>(owner.m_mutlref));
using mutrref_from_owner_t = decltype(forward_like<owner_t>(owner.m_mutrref));
using cobj_from_owner_t = decltype(forward_like<owner_t>(owner.m_cobj));
using clref_from_owner_t = decltype(forward_like<owner_t>(owner.m_clref));
using crref_from_owner_t = decltype(forward_like<owner_t>(owner.m_crref));

static_assert(is_same_v<mutobj_from_owner_t, int&&>);
static_assert(is_same_v<mutlref_from_owner_t, int&&>);
static_assert(is_same_v<mutrref_from_owner_t, int&&>);
static_assert(is_same_v<cobj_from_owner_t, const int&&>);
static_assert(is_same_v<clref_from_owner_t, const int&&>);
static_assert(is_same_v<crref_from_owner_t, const int&&>);

using owner_lref_t = decltype(owner_lref);
using mutobj_from_owner_lref_t = decltype(forward_like<owner_lref_t>(owner_lref.m_mutobj));
using mutlref_from_owner_lref_t = decltype(forward_like<owner_lref_t>(owner_lref.m_mutlref));
using mutrref_from_owner_lref_t = decltype(forward_like<owner_lref_t>(owner_lref.m_mutrref));
using cobj_from_owner_lref_t = decltype(forward_like<owner_lref_t>(owner_lref.m_cobj));
using clref_from_owner_lref_t = decltype(forward_like<owner_lref_t>(owner_lref.m_clref));
using crref_from_owner_lref_t = decltype(forward_like<owner_lref_t>(owner_lref.m_crref));

static_assert(is_same_v<mutobj_from_owner_lref_t, int&>);
static_assert(is_same_v<mutlref_from_owner_lref_t, int&>);
static_assert(is_same_v<mutrref_from_owner_lref_t, int&>);
static_assert(is_same_v<cobj_from_owner_lref_t, const int&>);
static_assert(is_same_v<clref_from_owner_lref_t, const int&>);
static_assert(is_same_v<crref_from_owner_lref_t, const int&>);

using owner_rref_t = decltype(owner_rref);
using mutobj_from_owner_rref_t = decltype(forward_like<owner_rref_t>(owner_rref.m_mutobj));
using mutlref_from_owner_rref_t = decltype(forward_like<owner_rref_t>(owner_rref.m_mutlref));
using mutrref_from_owner_rref_t = decltype(forward_like<owner_rref_t>(owner_rref.m_mutrref));
using cobj_from_owner_rref_t = decltype(forward_like<owner_rref_t>(owner_rref.m_cobj));
using clref_from_owner_rref_t = decltype(forward_like<owner_rref_t>(owner_rref.m_clref));
using crref_from_owner_rref_t = decltype(forward_like<owner_rref_t>(owner_rref.m_crref));

static_assert(is_same_v<mutobj_from_owner_rref_t, int&&>);
static_assert(is_same_v<mutlref_from_owner_rref_t, int&&>);
static_assert(is_same_v<mutrref_from_owner_rref_t, int&&>);
static_assert(is_same_v<cobj_from_owner_rref_t, const int&&>);
static_assert(is_same_v<clref_from_owner_rref_t, const int&&>);
static_assert(is_same_v<crref_from_owner_rref_t, const int&&>);

using owner_c_t = decltype(owner_c);
using mutobj_from_owner_c_t = decltype(forward_like<owner_c_t>(owner_c.m_mutobj));
using mutlref_from_owner_c_t = decltype(forward_like<owner_c_t>(owner_c.m_mutlref));
using mutrref_from_owner_c_t = decltype(forward_like<owner_c_t>(owner_c.m_mutrref));
using cobj_from_owner_c_t = decltype(forward_like<owner_c_t>(owner_c.m_cobj));
using clref_from_owner_c_t = decltype(forward_like<owner_c_t>(owner_c.m_clref));
using crref_from_owner_c_t = decltype(forward_like<owner_c_t>(owner_c.m_crref));

static_assert(is_same_v<mutobj_from_owner_c_t, const int&&>);
static_assert(is_same_v<mutlref_from_owner_c_t, const int&&>);
static_assert(is_same_v<mutrref_from_owner_c_t, const int&&>);
static_assert(is_same_v<cobj_from_owner_c_t, const int&&>);
static_assert(is_same_v<clref_from_owner_c_t, const int&&>);
static_assert(is_same_v<crref_from_owner_c_t, const int&&>);

using owner_clref_t = decltype(owner_clref);
using mutobj_from_owner_clref_t = decltype(forward_like<owner_clref_t>(owner_clref.m_mutobj));
using mutlref_from_owner_clref_t = decltype(forward_like<owner_clref_t>(owner_clref.m_mutlref));
using mutrref_from_owner_clref_t = decltype(forward_like<owner_clref_t>(owner_clref.m_mutrref));
using cobj_from_owner_clref_t = decltype(forward_like<owner_clref_t>(owner_clref.m_cobj));
using clref_from_owner_clref_t = decltype(forward_like<owner_clref_t>(owner_clref.m_clref));
using crref_from_owner_clref_t = decltype(forward_like<owner_clref_t>(owner_clref.m_crref));

static_assert(is_same_v<mutobj_from_owner_clref_t, const int&>);
static_assert(is_same_v<mutlref_from_owner_clref_t, const int&>);
static_assert(is_same_v<mutrref_from_owner_clref_t, const int&>);
static_assert(is_same_v<cobj_from_owner_clref_t, const int&>);
static_assert(is_same_v<clref_from_owner_clref_t, const int&>);
static_assert(is_same_v<crref_from_owner_clref_t, const int&>);

using owner_crref_t = decltype(owner_crref);
using mutobj_from_owner_crref_t = decltype(forward_like<owner_crref_t>(owner_crref.m_mutobj));
using mutlref_from_owner_crref_t = decltype(forward_like<owner_crref_t>(owner_crref.m_mutlref));
using mutrref_from_owner_crref_t = decltype(forward_like<owner_crref_t>(owner_crref.m_mutrref));
using cobj_from_owner_crref_t = decltype(forward_like<owner_crref_t>(owner_crref.m_cobj));
using clref_from_owner_crref_t = decltype(forward_like<owner_crref_t>(owner_crref.m_clref));
using crref_from_owner_crref_t = decltype(forward_like<owner_crref_t>(owner_crref.m_crref));

static_assert(is_same_v<mutobj_from_owner_crref_t, const int&&>);
static_assert(is_same_v<mutlref_from_owner_crref_t, const int&&>);
static_assert(is_same_v<mutrref_from_owner_crref_t, const int&&>);
static_assert(is_same_v<cobj_from_owner_crref_t, const int&&>);
static_assert(is_same_v<clref_from_owner_crref_t, const int&&>);
static_assert(is_same_v<crref_from_owner_crref_t, const int&&>);

int main() {} // COMPILE-ONLY
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -786,6 +786,20 @@ STATIC_ASSERT(__cpp_lib_format == 202110L);
#endif
#endif

#if _HAS_CXX23
#ifndef __cpp_lib_forward_like
#error __cpp_lib_forward_like is not defined
#elif __cpp_lib_forward_like != 202207L
#error __cpp_lib_forward_like is not 202207L
#else
STATIC_ASSERT(__cpp_lib_forward_like == 202207L);
#endif
#else
#ifdef __cpp_lib_forward_like
#error __cpp_lib_forward_like is defined
#endif
#endif

#if _HAS_CXX17
#ifndef __cpp_lib_gcd_lcm
#error __cpp_lib_gcd_lcm is not defined
Expand Down