Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 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
37 changes: 37 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
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,27 @@ _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 _UnrefT = remove_reference_t<_Ty>;
using _UnrefU = remove_reference_t<_Uty>;
if constexpr (is_const_v<_UnrefT>) {
if constexpr (is_lvalue_reference_v<_Ty>) {
return static_cast<const _UnrefU&>(_Ux);
} else {
return static_cast<const _UnrefU&&>(_Ux);
}
} else {
if constexpr (is_lvalue_reference_v<_Ty>) {
return static_cast<_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 @@ -326,6 +326,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 @@ -1496,6 +1497,7 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect
#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 @@ -502,6 +502,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\P2517R1_apply_conditional_noexcept
tests\VSO_0000000_allocator_propagation
tests\VSO_0000000_any_calling_conventions
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
59 changes: 59 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,59 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <type_traits>
#include <utility>

using namespace std;

struct U {}; // class type so const-qualification is not stripped from a prvalue
using CU = const U;
using T = int;
using CT = const T;

U u{};
const U& cu = u;

static_assert(is_same_v<decltype(forward_like<T>(U{})), U&&>);
static_assert(is_same_v<decltype(forward_like<T>(CU{})), CU&&>);
static_assert(is_same_v<decltype(forward_like<T>(u)), U&&>);
static_assert(is_same_v<decltype(forward_like<T>(cu)), CU&&>);
static_assert(is_same_v<decltype(forward_like<T>(move(u))), U&&>);
static_assert(is_same_v<decltype(forward_like<T>(move(cu))), CU&&>);

static_assert(is_same_v<decltype(forward_like<CT>(U{})), CU&&>);
static_assert(is_same_v<decltype(forward_like<CT>(CU{})), CU&&>);
static_assert(is_same_v<decltype(forward_like<CT>(u)), CU&&>);
static_assert(is_same_v<decltype(forward_like<CT>(cu)), CU&&>);
static_assert(is_same_v<decltype(forward_like<CT>(move(u))), CU&&>);
static_assert(is_same_v<decltype(forward_like<CT>(move(cu))), CU&&>);

static_assert(is_same_v<decltype(forward_like<T&>(U{})), U&>);
static_assert(is_same_v<decltype(forward_like<T&>(CU{})), CU&>);
static_assert(is_same_v<decltype(forward_like<T&>(u)), U&>);
static_assert(is_same_v<decltype(forward_like<T&>(cu)), CU&>);
static_assert(is_same_v<decltype(forward_like<T&>(move(u))), U&>);
static_assert(is_same_v<decltype(forward_like<T&>(move(cu))), CU&>);

static_assert(is_same_v<decltype(forward_like<CT&>(U{})), CU&>);
static_assert(is_same_v<decltype(forward_like<CT&>(CU{})), CU&>);
static_assert(is_same_v<decltype(forward_like<CT&>(u)), CU&>);
static_assert(is_same_v<decltype(forward_like<CT&>(cu)), CU&>);
static_assert(is_same_v<decltype(forward_like<CT&>(move(u))), CU&>);
static_assert(is_same_v<decltype(forward_like<CT&>(move(cu))), CU&>);

static_assert(is_same_v<decltype(forward_like<T&&>(U{})), U&&>);
static_assert(is_same_v<decltype(forward_like<T&&>(CU{})), CU&&>);
static_assert(is_same_v<decltype(forward_like<T&&>(u)), U&&>);
static_assert(is_same_v<decltype(forward_like<T&&>(cu)), CU&&>);
static_assert(is_same_v<decltype(forward_like<T&&>(move(u))), U&&>);
static_assert(is_same_v<decltype(forward_like<T&&>(move(cu))), CU&&>);

static_assert(is_same_v<decltype(forward_like<CT&&>(U{})), CU&&>);
static_assert(is_same_v<decltype(forward_like<CT&&>(CU{})), CU&&>);
static_assert(is_same_v<decltype(forward_like<CT&&>(u)), CU&&>);
static_assert(is_same_v<decltype(forward_like<CT&&>(cu)), CU&&>);
static_assert(is_same_v<decltype(forward_like<CT&&>(move(u))), CU&&>);
static_assert(is_same_v<decltype(forward_like<CT&&>(move(cu))), CU&&>);

int main() {} // COMPILE-ONLY
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,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