libstdc++: Fix common_type specializations for duration

My recent change to implement P0548 ("common_type and duration") was not
correct. The result of common_type_t<duration<R,P>, duration<R,P>>
should be duration<common_type_t<R>, P::type>, not duration<R, P::type>.
The common_type specialization for two different duration types was
correct, but the specializations for a single duration type (which only
exist to optimize compilation time) were wrong.

This fixes the partial specializations of common_type for a single
duration type, and also the return types of duration::operator+ and
duration::operator- which are supposed to use common_type_t<duration>.

libstdc++-v3/ChangeLog:

	* include/std/chrono (common_type): Fix partial specializations
	for a single duration type to use the common_type of the rep.
	(duration::operator+, duration::operator-): Fix return types
	to also use the common_type of the rep.
	* testsuite/20_util/duration/requirements/reduced_period.cc:
	Check duration using a rep that has common_type specialized.
This commit is contained in:
Jonathan Wakely 2020-08-28 23:41:13 +01:00
parent 82db1a42e9
commit f2f48b68a6
2 changed files with 64 additions and 6 deletions

View File

@ -114,13 +114,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Rep, typename _Period>
struct common_type<chrono::duration<_Rep, _Period>,
chrono::duration<_Rep, _Period>>
{ using type = chrono::duration<_Rep, typename _Period::type>; };
{
using type = chrono::duration<typename common_type<_Rep>::type,
typename _Period::type>;
};
/// Specialization of common_type for one chrono::duration type.
/// @relates duration
template<typename _Rep, typename _Period>
struct common_type<chrono::duration<_Rep, _Period>>
{ using type = chrono::duration<_Rep, typename _Period::type>; };
{
using type = chrono::duration<typename common_type<_Rep>::type,
typename _Period::type>;
};
// 20.11.4.3 specialization of common_type (for time_point, sfinae-friendly)
@ -463,13 +469,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// 20.11.5.3 arithmetic
constexpr duration<rep, period>
constexpr duration<typename common_type<rep>::type, period>
operator+() const
{ return *this; }
{ return duration<typename common_type<rep>::type, period>(__r); }
constexpr duration<rep, period>
constexpr duration<typename common_type<rep>::type, period>
operator-() const
{ return duration(-__r); }
{ return duration<typename common_type<rep>::type, period>(-__r); }
_GLIBCXX17_CONSTEXPR duration&
operator++()

View File

@ -129,3 +129,55 @@ test02()
static_assert( is_same<decltype(-d3), common_type<D3>::type>::value,
"unary - returns the reduced duration" );
}
template<typename T>
struct Number
{
explicit
Number(T t = 0) : i(t)
{ }
template<typename U, bool B = std::is_convertible<U, T>::value,
typename = typename std::enable_if<B>::type>
explicit
Number(Number<U> n) : i(n.i)
{ }
T i = 0;
Number& operator+=(Number n) { i += n.i; return *this; }
Number& operator-=(Number n) { i -= n.i; return *this; }
Number& operator*=(Number n) { i *= n.i; return *this; }
Number& operator/=(Number n) { i /= n.i; return *this; }
Number& operator%=(Number n) { i %= n.i; return *this; }
Number operator+(Number n) { return { i + n.i }; }
Number operator-(Number n) { return { i - n.i }; }
Number operator*(Number n) { return { i * n.i }; }
Number operator/(Number n) { return { i / n.i }; }
Number operator%(Number n) { return { i % n.i }; }
};
namespace std
{
// Specialise common_type to give a different type
template<>
struct common_type<Number<int>, Number<int>>
{ using type = Number<long>; };
}
void
test03()
{
using D4 = duration<Number<int>, ratio<49, 21>>;
static_assert( is_same<common_type<D4>::type,
duration<Number<long>, ratio<7, 3>>>::value,
"common_type_t<duration<R,P>> uses common_type_t<R>" );
D4 d4;
static_assert( is_same<decltype(+d4), common_type<D4>::type>::value,
"unary + returns type with common_type_t<D4::rep> as rep" );
static_assert( is_same<decltype(-d4), common_type<D4>::type>::value,
"unary - returns type with common_type_t<D4::rep> as rep" );
}