libstdc++: use concrete return type for std::forward_like
Inspired by https://github.com/llvm/llvm-project/issues/101614 this inverts the relationship between forward_like and __like_t so that forward_like is defined in terms of __like_t and with a concrete return type. __like_t in turn is defined via partial specializations that pattern match on the const- and reference-ness of T. This turns out to be more SFINAE friendly and significantly cheaper to compile than the previous implementation. libstdc++-v3/ChangeLog: * include/bits/move.h (__like_impl): New metafunction. (__like_t): Redefine in terms of __like_impl. (forward_like): Redefine in terms of __like_t. * testsuite/20_util/forward_like/2_neg.cc: Don't expect error outside the immediate context anymore. Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
This commit is contained in:
parent
db9834aead
commit
8256d5c009
2 changed files with 26 additions and 27 deletions
|
@ -88,31 +88,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
#if __glibcxx_forward_like // C++ >= 23
|
||||
template<typename _Tp, typename _Up>
|
||||
[[nodiscard]]
|
||||
constexpr decltype(auto)
|
||||
forward_like(_Up&& __x) noexcept
|
||||
{
|
||||
constexpr bool __as_rval = is_rvalue_reference_v<_Tp&&>;
|
||||
|
||||
if constexpr (is_const_v<remove_reference_t<_Tp>>)
|
||||
{
|
||||
using _Up2 = remove_reference_t<_Up>;
|
||||
if constexpr (__as_rval)
|
||||
return static_cast<const _Up2&&>(__x);
|
||||
else
|
||||
return static_cast<const _Up2&>(__x);
|
||||
}
|
||||
else
|
||||
{
|
||||
if constexpr (__as_rval)
|
||||
return static_cast<remove_reference_t<_Up>&&>(__x);
|
||||
else
|
||||
return static_cast<_Up&>(__x);
|
||||
}
|
||||
}
|
||||
struct __like_impl; // _Tp must be a reference and _Up an lvalue reference
|
||||
|
||||
template<typename _Tp, typename _Up>
|
||||
using __like_t = decltype(std::forward_like<_Tp>(std::declval<_Up>()));
|
||||
struct __like_impl<_Tp&, _Up&>
|
||||
{ using type = _Up&; };
|
||||
|
||||
template<typename _Tp, typename _Up>
|
||||
struct __like_impl<const _Tp&, _Up&>
|
||||
{ using type = const _Up&; };
|
||||
|
||||
template<typename _Tp, typename _Up>
|
||||
struct __like_impl<_Tp&&, _Up&>
|
||||
{ using type = _Up&&; };
|
||||
|
||||
template<typename _Tp, typename _Up>
|
||||
struct __like_impl<const _Tp&&, _Up&>
|
||||
{ using type = const _Up&&; };
|
||||
|
||||
template<typename _Tp, typename _Up>
|
||||
using __like_t = typename __like_impl<_Tp&&, _Up&>::type;
|
||||
|
||||
template<typename _Tp, typename _Up>
|
||||
[[nodiscard]]
|
||||
constexpr __like_t<_Tp, _Up>
|
||||
forward_like(_Up&& __x) noexcept
|
||||
{ return static_cast<__like_t<_Tp, _Up>>(__x); }
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,9 +2,7 @@
|
|||
|
||||
#include <utility>
|
||||
|
||||
auto x1 = std::forward_like<void>(1); // { dg-error "here" }
|
||||
auto x1 = std::forward_like<void>(1); // { dg-error "no match" }
|
||||
// { dg-error "forming reference to void" "" { target *-*-* } 0 }
|
||||
auto x2 = std::forward_like<void()const>(1); // { dg-error "here" }
|
||||
auto x2 = std::forward_like<void()const>(1); // { dg-error "no match" }
|
||||
// { dg-error "forming reference to qualified function" "" { target *-*-* } 0 }
|
||||
|
||||
// { dg-prune-output "inconsistent deduction for auto return type" } // PR111484
|
||||
|
|
Loading…
Add table
Reference in a new issue