Implement std::common_reference for C++20

* include/std/type_traits (__do_common_type_impl): Implement
	additional COND-RES(CREF(D1), CRED(D2)) condition for C++20.
	(basic_common_reference, common_reference, common_reference_t): Define
	for C++20.
	* testsuite/20_util/common_reference/requirements/alias_decl.cc: New
	test.
	* testsuite/20_util/common_reference/requirements/
	explicit_instantiation.cc: New test.
	* testsuite/20_util/common_reference/requirements/typedefs.cc: New
	test.

From-SVN: r275594
This commit is contained in:
Jonathan Wakely 2019-09-10 17:28:27 +01:00 committed by Jonathan Wakely
parent e8b0314a58
commit 0f8b14ee8a
5 changed files with 353 additions and 6 deletions

View File

@ -1,5 +1,16 @@
2019-09-10 Jonathan Wakely <jwakely@redhat.com>
* include/std/type_traits (__do_common_type_impl): Implement
additional COND-RES(CREF(D1), CRED(D2)) condition for C++20.
(basic_common_reference, common_reference, common_reference_t): Define
for C++20.
* testsuite/20_util/common_reference/requirements/alias_decl.cc: New
test.
* testsuite/20_util/common_reference/requirements/
explicit_instantiation.cc: New test.
* testsuite/20_util/common_reference/requirements/typedefs.cc: New
test.
* include/std/charconv (to_chars): Rename to __to_chars_i. Define
non-template overloads for each signed and unsigned integer type and
char. Define deleted overload for bool (LWG 3266).

View File

@ -2189,6 +2189,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct conditional<false, _Iftrue, _Iffalse>
{ typedef _Iffalse type; };
// __remove_cvref_t (std::remove_cvref_t for C++11).
template<typename _Tp>
using __remove_cvref_t
= typename remove_cv<typename remove_reference<_Tp>::type>::type;
/// common_type
template<typename... _Tp>
struct common_type;
@ -2201,12 +2206,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
using __cond_t
= decltype(true ? std::declval<_Tp>() : std::declval<_Up>());
// if decay_t<decltype(false ? declval<D1>() : declval<D2>())>
// denotes a valid type, let C denote that type.
template<typename _Tp, typename _Up>
static __success_type<typename decay<__cond_t<_Tp, _Up>>::type>
static __success_type<__decay_t<__cond_t<_Tp, _Up>>>
_S_test(int);
#if __cplusplus > 201703L
// Otherwise, if COND-RES(CREF(D1), CREF(D2)) denotes a type,
// let C denote the type decay_t<COND-RES(CREF(D1), CREF(D2))>.
template<typename _Tp, typename _Up>
static __success_type<__remove_cvref_t<__cond_t<const _Tp&, const _Up&>>>
_S_test_2(int);
#endif
template<typename, typename>
static __failure_type
_S_test_2(...);
template<typename _Tp, typename _Up>
static decltype(_S_test_2<_Tp, _Up>(0))
_S_test(...);
};
@ -2304,11 +2323,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return __declval<_Tp>(0);
}
// __remove_cvref_t (std::remove_cvref_t for C++11).
template<typename _Tp>
using __remove_cvref_t
= typename remove_cv<typename remove_reference<_Tp>::type>::type;
/// result_of
template<typename _Signature>
class result_of;
@ -3248,6 +3262,164 @@ template <typename _From, typename _To>
{ return __builtin_is_constant_evaluated(); }
#endif
template<typename _From, typename _To>
using __copy_cv = typename __match_cv_qualifiers<_From, _To>::__type;
template<typename _Xp, typename _Yp>
using __cond_res
= decltype(false ? declval<_Xp(&)()>()() : declval<_Yp(&)()>()());
template<typename _Ap, typename _Bp, typename = void>
struct __common_ref_impl
{ };
// [meta.trans.other], COMMON-REF(A, B)
template<typename _Ap, typename _Bp>
using __common_ref = typename __common_ref_impl<_Ap, _Bp>::type;
// If A and B are both lvalue reference types, ...
template<typename _Xp, typename _Yp>
struct __common_ref_impl<_Xp&, _Yp&,
__void_t<__cond_res<__copy_cv<_Xp, _Yp>&, __copy_cv<_Yp, _Xp>&>>>
{ using type = __cond_res<__copy_cv<_Xp, _Yp>&, __copy_cv<_Yp, _Xp>&>; };
// let C be remove_reference_t<COMMON-REF(X&, Y&)>&&
template<typename _Xp, typename _Yp>
using __common_ref_C = remove_reference_t<__common_ref<_Xp&, _Yp&>>&&;
// If A and B are both rvalue reference types, ...
template<typename _Xp, typename _Yp>
struct __common_ref_impl<_Xp&&, _Yp&&,
_Require<is_convertible<_Xp&&, __common_ref_C<_Xp, _Yp>>,
is_convertible<_Yp&&, __common_ref_C<_Xp, _Yp>>>>
{ using type = __common_ref_C<_Xp, _Yp>; };
// let D be COMMON-REF(const X&, Y&)
template<typename _Xp, typename _Yp>
using __common_ref_D = __common_ref<const _Xp&, _Yp&>;
// If A is an rvalue reference and B is an lvalue reference, ...
template<typename _Xp, typename _Yp>
struct __common_ref_impl<_Xp&&, _Yp&,
_Require<is_convertible<_Xp&&, __common_ref_D<_Xp, _Yp>>>>
{ using type = __common_ref_D<_Xp, _Yp>; };
// If A is an lvalue reference and B is an rvalue reference, ...
template<typename _Xp, typename _Yp>
struct __common_ref_impl<_Xp&, _Yp&&>
: __common_ref_impl<_Yp&&, _Xp&>
{ };
template<typename _Tp, typename _Up,
template<typename> class _TQual, template<typename> class _UQual>
struct basic_common_reference
{ };
template<typename _Tp>
struct __xref
{ template<typename _Up> using __type = __copy_cv<_Tp, _Up>; };
template<typename _Tp>
struct __xref<_Tp&>
{ template<typename _Up> using __type = __copy_cv<_Tp, _Up>&; };
template<typename _Tp>
struct __xref<_Tp&&>
{ template<typename _Up> using __type = __copy_cv<_Tp, _Up>&&; };
template<typename _Tp1, typename _Tp2>
using __basic_common_ref
= typename basic_common_reference<remove_cvref_t<_Tp1>,
remove_cvref_t<_Tp2>,
__xref<_Tp1>::template __type,
__xref<_Tp2>::template __type>::type;
template<typename... _Tp>
struct common_reference;
template<typename... _Tp>
using common_reference_t = typename common_reference<_Tp...>::type;
// If sizeof...(T) is zero, there shall be no member type.
template<>
struct common_reference<>
{ };
// If sizeof...(T) is one ...
template<typename _Tp0>
struct common_reference<_Tp0>
{ using type = _Tp0; };
template<typename _Tp1, typename _Tp2, int _Bullet = 1, typename = void>
struct __common_reference_impl
: __common_reference_impl<_Tp1, _Tp2, _Bullet + 1>
{ };
// If sizeof...(T) is two ...
template<typename _Tp1, typename _Tp2>
struct common_reference<_Tp1, _Tp2>
: __common_reference_impl<_Tp1, _Tp2>
{ };
// If T1 and T2 are reference types and COMMON-REF(T1, T2) is well-formed, ...
template<typename _Tp1, typename _Tp2>
struct __common_reference_impl<_Tp1&, _Tp2&, 1,
void_t<__common_ref<_Tp1&, _Tp2&>>>
{ using type = __common_ref<_Tp1&, _Tp2&>; };
template<typename _Tp1, typename _Tp2>
struct __common_reference_impl<_Tp1&&, _Tp2&&, 1,
void_t<__common_ref<_Tp1&&, _Tp2&&>>>
{ using type = __common_ref<_Tp1&&, _Tp2&&>; };
template<typename _Tp1, typename _Tp2>
struct __common_reference_impl<_Tp1&, _Tp2&&, 1,
void_t<__common_ref<_Tp1&, _Tp2&&>>>
{ using type = __common_ref<_Tp1&, _Tp2&&>; };
template<typename _Tp1, typename _Tp2>
struct __common_reference_impl<_Tp1&&, _Tp2&, 1,
void_t<__common_ref<_Tp1&&, _Tp2&>>>
{ using type = __common_ref<_Tp1&&, _Tp2&>; };
// Otherwise, if basic_common_reference<...>::type is well-formed, ...
template<typename _Tp1, typename _Tp2>
struct __common_reference_impl<_Tp1, _Tp2, 2,
void_t<__basic_common_ref<_Tp1, _Tp2>>>
{ using type = __basic_common_ref<_Tp1, _Tp2>; };
// Otherwise, if COND-RES(T1, T2) is well-formed, ...
template<typename _Tp1, typename _Tp2>
struct __common_reference_impl<_Tp1, _Tp2, 3,
void_t<__cond_res<_Tp1, _Tp2>>>
{ using type = __cond_res<_Tp1, _Tp2>; };
// Otherwise, if common_type_t<T1, T2> is well-formed, ...
template<typename _Tp1, typename _Tp2>
struct __common_reference_impl<_Tp1, _Tp2, 4,
void_t<common_type_t<_Tp1, _Tp2>>>
{ using type = common_type_t<_Tp1, _Tp2>; };
// Otherwise, there shall be no member type.
template<typename _Tp1, typename _Tp2>
struct __common_reference_impl<_Tp1, _Tp2, 5, void>
{ };
// Otherwise, if sizeof...(T) is greater than two, ...
template<typename _Tp1, typename _Tp2, typename... _Rest>
struct common_reference<_Tp1, _Tp2, _Rest...>
: __common_type_fold<common_reference<_Tp1, _Tp2>,
__common_type_pack<_Rest...>>
{ };
// Reuse __common_type_fold for common_reference<T1, T2, Rest...>
template<typename _Tp1, typename _Tp2, typename... _Rest>
struct __common_type_fold<common_reference<_Tp1, _Tp2>,
__common_type_pack<_Rest...>,
void_t<common_reference_t<_Tp1, _Tp2>>>
: public common_reference<common_reference_t<_Tp1, _Tp2>, _Rest...>
{ };
#endif // C++2a
_GLIBCXX_END_NAMESPACE_VERSION

View File

@ -0,0 +1,30 @@
// Copyright (C) 2019 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// { dg-options "-std=gnu++2a" }
// { dg-do compile { target c++2a } }
#include <type_traits>
using namespace std;
static_assert( is_same_v<common_reference<int>::type,
common_reference_t<int>>);
static_assert( is_same_v<common_reference<int&, const int&>::type,
common_reference_t<int&, const int&>>);
static_assert( is_same_v<common_reference<int, long&, char, unsigned&>::type,
common_reference_t<int, long&, char, unsigned&>>);

View File

@ -0,0 +1,42 @@
// Copyright (C) 2019 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// NB: This file is for testing type_traits with NO OTHER INCLUDES.
// { dg-options "-std=gnu++2a" }
// { dg-do compile { target c++2a } }
#include <type_traits>
using test_type1 = int;
using test_type2 = int&;
using test_type3 = double;
using test_type4 = float&;
using test_type5 = void;
using test_type6 = const void;
namespace std
{
template struct common_reference<>;
template struct common_reference<test_type1>;
template struct common_reference<test_type1, test_type2>;
template struct common_reference<test_type1, test_type2, test_type3>;
template struct common_reference<test_type1, test_type2, test_type3, test_type4>;
template struct common_reference<test_type5>;
template struct common_reference<test_type5, test_type6>;
}

View File

@ -0,0 +1,92 @@
// Copyright (C) 2019 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// { dg-options "-std=gnu++2a" }
// { dg-do compile { target c++2a } }
#include <type_traits>
template<typename T, typename = void>
struct has_type : std::false_type { };
template<typename T>
struct has_type<T, std::void_t<typename T::type>> : std::true_type { };
template<typename... T>
constexpr bool
has_common_ref()
{
return has_type<std::common_reference<T...>>::value;
}
using std::is_same_v;
using std::common_reference_t;
void test01()
{
static_assert( !has_common_ref<>() );
static_assert( !has_common_ref<char(*)(), int(*)()>() );
static_assert( !has_common_ref<void*, int>() );
static_assert( is_same_v<common_reference_t<int>, int> );
static_assert( is_same_v<common_reference_t<int&>, int&> );
static_assert( is_same_v<common_reference_t<void>, void> );
static_assert( is_same_v<common_reference_t<const void>, const void> );
static_assert( is_same_v<common_reference_t<const void, void>, void> );
static_assert( is_same_v<common_reference_t<void(*const)(), void(*)()>, void(*)()> );
static_assert( is_same_v<common_reference_t<int, int>, int> );
static_assert( is_same_v<common_reference_t<int&, int>, int> );
static_assert( is_same_v<common_reference_t<int, int&>, int> );
static_assert( is_same_v<common_reference_t<int&&, int>, int> );
static_assert( is_same_v<common_reference_t<int&, int&>, int&> );
static_assert( is_same_v<common_reference_t<int&, int&&>, const int&> );
static_assert( is_same_v<common_reference_t<int&&, int&>, const int&> );
static_assert( is_same_v<common_reference_t<int&&, int&&>, int&&> );
static_assert( is_same_v<common_reference_t<int&&, const int&&>, const int&&> );
static_assert( is_same_v<common_reference_t<int&, int&, int&&>, const int&> );
static_assert( is_same_v<common_reference_t<int&&, int&, int&>, const int&> );
static_assert( is_same_v<common_reference_t<char&, int&>, int> );
static_assert( is_same_v<common_reference_t<long&, int&>, long> );
}
struct A { };
struct B { };
struct C { };
template<template<typename> class AQual, template<typename> class BQual>
struct std::basic_common_reference<A, B, AQual, BQual>
{
using type = BQual<AQual<C>>;
};
static_assert( is_same_v<common_reference_t<A, B>, C> );
static_assert( is_same_v<common_reference_t<A&, B>, C&> );
static_assert( is_same_v<common_reference_t<A&, const B>, C&> );
static_assert( is_same_v<common_reference_t<const A, B&>, const C&> );
static_assert( is_same_v<common_reference_t<const A&, B&&>, const C&> );
static_assert( is_same_v<common_reference_t<const A, B&&>, const C&&> );
struct D { };
struct E { };
struct F { };
template<> struct std::common_type<D, E> { using type = F; };
static_assert( is_same_v<common_reference_t<D, E>, F> );
static_assert( is_same_v<common_reference_t<D&, E>, F> );
static_assert( is_same_v<common_reference_t<D&, E&&>, F> );