diff --git a/stl/inc/__msvc_iter_core.hpp b/stl/inc/__msvc_iter_core.hpp index 697da4cf28..f552728d36 100644 --- a/stl/inc/__msvc_iter_core.hpp +++ b/stl/inc/__msvc_iter_core.hpp @@ -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 -using _With_reference = _Ty&; - -template -concept _Can_reference = requires { - typename _With_reference<_Ty>; -}; - template concept _Dereferenceable = requires(_Ty& __t) { { *__t } -> _Can_reference; diff --git a/stl/inc/utility b/stl/inc/utility index 38633cd38a..c649a21290 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -788,6 +788,22 @@ _NODISCARD constexpr bool in_range(const _Ty _Value) noexcept { return true; } + +#ifdef __cpp_lib_concepts +template +using _With_reference = _Ty&; + +template +concept _Can_reference = requires { + typename _With_reference<_Ty>; +}; +#else // __cpp_lib_concepts +template +inline constexpr bool _Can_reference = false; + +template +inline constexpr bool _Can_reference<_Ty, void_t<_Ty&>> = true; +#endif // __cpp_lib_concepts #endif // _HAS_CXX20 #if _HAS_CXX23 @@ -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 +_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(_Ux); + } else { + return static_cast(_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 diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 0d556fe0a2..bf00b94929 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -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::error() @@ -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 diff --git a/tests/std/test.lst b/tests/std/test.lst index 4df98042a1..fcbeb035e2 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -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 diff --git a/tests/std/tests/P2445R1_forward_like/env.lst b/tests/std/tests/P2445R1_forward_like/env.lst new file mode 100644 index 0000000000..642f530ffa --- /dev/null +++ b/tests/std/tests/P2445R1_forward_like/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp b/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp new file mode 100644 index 0000000000..3787ed8055 --- /dev/null +++ b/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp @@ -0,0 +1,72 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include + +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(U{})), U&&>); +static_assert(is_same_v(CU{})), CU&&>); +static_assert(is_same_v(u)), U&&>); +static_assert(is_same_v(cu)), CU&&>); +static_assert(is_same_v(move(u))), U&&>); +static_assert(is_same_v(move(cu))), CU&&>); + +static_assert(is_same_v(U{})), CU&&>); +static_assert(is_same_v(CU{})), CU&&>); +static_assert(is_same_v(u)), CU&&>); +static_assert(is_same_v(cu)), CU&&>); +static_assert(is_same_v(move(u))), CU&&>); +static_assert(is_same_v(move(cu))), CU&&>); + +static_assert(is_same_v(U{})), U&>); +static_assert(is_same_v(CU{})), CU&>); +static_assert(is_same_v(u)), U&>); +static_assert(is_same_v(cu)), CU&>); +static_assert(is_same_v(move(u))), U&>); +static_assert(is_same_v(move(cu))), CU&>); + +static_assert(is_same_v(U{})), CU&>); +static_assert(is_same_v(CU{})), CU&>); +static_assert(is_same_v(u)), CU&>); +static_assert(is_same_v(cu)), CU&>); +static_assert(is_same_v(move(u))), CU&>); +static_assert(is_same_v(move(cu))), CU&>); + +static_assert(is_same_v(U{})), U&&>); +static_assert(is_same_v(CU{})), CU&&>); +static_assert(is_same_v(u)), U&&>); +static_assert(is_same_v(cu)), CU&&>); +static_assert(is_same_v(move(u))), U&&>); +static_assert(is_same_v(move(cu))), CU&&>); + +static_assert(is_same_v(U{})), CU&&>); +static_assert(is_same_v(CU{})), CU&&>); +static_assert(is_same_v(u)), CU&&>); +static_assert(is_same_v(cu)), CU&&>); +static_assert(is_same_v(move(u))), CU&&>); +static_assert(is_same_v(move(cu))), CU&&>); + +static_assert(noexcept(forward_like(u))); + +constexpr bool test() { + int val = 1729; + auto&& result = forward_like(val); + static_assert(is_same_v); + assert(&result == &val); + return true; +} + +static_assert(test()); + +int main() {} // COMPILE-ONLY diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp index 72353acb92..fd14031bd1 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp @@ -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