year_month*
arithmetic rejects durations convertible to yearsSection: 30.8 [time.cal] Status: C++20 Submitter: Tomasz Kamiński Opened: 2019-08-15 Last modified: 2021-02-25
Priority: 2
View all issues with C++20 status.
Discussion:
Currently, the year_month*
types (year_month
,
year_month_day
) provide separate arithmetic operators with
duration type of years
or months
. This is an intentional
optimization that avoids performing modulo arithmetic in the former case.
year_month*
types
with durations that are convertible to years
(and by
consequence to months
) ambiguous. For example, the following
code is ambiguous:
using decades = duration<int, ratio_multiply<ratio<10>, years::period>>;
auto ymd = 2001y/January/1d;
ymd += decades(1); // error, ambiguous
while less usual durations that are only convertible to months
work correctly:
using decamonths = duration<int, ratio_multiply<ratio<10>, months::period>>; auto ymd = 2001y/January/1d; ymd += decamonths(1);
The example implementation resolves the issues by making sure that the
years
overload will be preferred in case of ambiguity, by declaring the
months
overload a function template with a default argument for its parameter
(suggested by Tim Song):
template<class = unspecified> constexpr year_month_weekday& operator+=(const months& m) noexcept; constexpr year_month_weekday& operator+=(const years& m) noexcept;
[2019-09-14 Priority set to 2 based on reflector discussion]
[2019-09-14; Tomasz and Howard provide concrete wording]
Previous resolution [SUPERSEDED]:
This wording is relative to N4830.
[Drafting note: Suggested wording below assumes that we can add a Constraints: to a signature where the constraint does not apply to a deduced template. We have examples of such constraints in other parts of the WD (e.g. 20.3.1.3.2 [unique.ptr.single.ctor]/p15, 20.3.1.3.4 [unique.ptr.single.asgn]/p1). And we have the old form "does not participate …" being used for non-deduced templates in several places as well (e.g. 22.3.2 [pairs.pair]/p5).
There are several ways of implementing such a constraint, such as adding a gratuitous template parameter.]
Modify 30.8.13.2 [time.cal.ym.members] as indicated:
constexpr year_month& operator+=(const months& dm) noexcept;-?- Constraints: The argument supplied by the caller for the
-4- Effects:months
parameter is not implicitly convertible toyears
.*this = *this + dm
. […]constexpr year_month& operator-=(const months& dm) noexcept;-?- Constraints: The argument supplied by the caller for the
-6- Effects:months
parameter is not implicitly convertible toyears
.*this = *this - dm
. […]Modify 30.8.13.3 [time.cal.ym.nonmembers] as indicated:
constexpr year_month operator+(const year_month& ym, const months& dm) noexcept;-?- Constraints: The argument supplied by the caller for the
-3- Returns: Amonths
parameter is not implicitly convertible toyears
.year_month
valuez
such thatz - ym == dm
. […]constexpr year_month operator+(const months& dm, const year_month& ym) noexcept;-?- Constraints: The argument supplied by the caller for the
-5- Returns:months
parameter is not implicitly convertible toyears
.ym + dm
.constexpr year_month operator-(const year_month& ym, const months& dm) noexcept;-?- Constraints: The argument supplied by the caller for the
-6- Returns:months
parameter is not implicitly convertible toyears
.ym + -dm
.Modify 30.8.14.2 [time.cal.ymd.members] as indicated:
constexpr year_month_day& operator+=(const months& m) noexcept;-?- Constraints: The argument supplied by the caller for the
-7- Effects:months
parameter is not implicitly convertible toyears
.*this = *this + m
. […]constexpr year_month_day& operator-=(const months& m) noexcept;-?- Constraints: The argument supplied by the caller for the
-9- Effects:months
parameter is not implicitly convertible toyears
.*this = *this - m
. […]Modify 30.8.14.3 [time.cal.ymd.nonmembers] as indicated:
constexpr year_month_day operator+(const year_month_day& ymd, const months& dm) noexcept;-?- Constraints: The argument supplied by the caller for the
-3- Returns:months
parameter is not implicitly convertible toyears
.(ymd.year() / ymd.month() + dm) / ymd.day()
. […]constexpr year_month_day operator+(const months& dm, const year_month_day& ymd) noexcept;-?- Constraints: The argument supplied by the caller for the
-5- Returns:months
parameter is not implicitly convertible toyears
.ymd + dm
.constexpr year_month_day operator+(const months& dm, const year_month_day& ymd) noexcept;-?- Constraints: The argument supplied by the caller for the
-6- Returns:months
parameter is not implicitly convertible toyears
.ymd + (-dm)
.Modify 30.8.15.2 [time.cal.ymdlast.members] as indicated:
constexpr year_month_day_last& operator+=(const months& m) noexcept;-?- Constraints: The argument supplied by the caller for the
-2- Effects:months
parameter is not implicitly convertible toyears
.*this = *this + m
. […]constexpr year_month_day_last& operator-=(const months& m) noexcept;-?- Constraints: The argument supplied by the caller for the
-4- Effects:months
parameter is not implicitly convertible toyears
.*this = *this - m
. […]Modify 30.8.15.3 [time.cal.ymdlast.nonmembers] as indicated:
constexpr year_month_day_last operator+(const year_month_day_last& ymdl, const months& dm) noexcept;-?- Constraints: The argument supplied by the caller for the
-3- Returns:months
parameter is not implicitly convertible toyears
.(ymdl.year() / ymdl.month() + dm) / last
.constexpr year_month_day_last operator+(const months& dm, const year_month_day_last& ymdl) noexcept;-?- Constraints: The argument supplied by the caller for the
-4- Returns:months
parameter is not implicitly convertible toyears
.ymdl + dm
.constexpr year_month_day_last operator-(const year_month_day_last& ymdl, const months& dm) noexcept;-?- Constraints: The argument supplied by the caller for the
-5- Returns:months
parameter is not implicitly convertible toyears
.ymdl + (-dm)
.Modify 30.8.16.2 [time.cal.ymwd.members] as indicated:
constexpr year_month_weekday& operator+=(const months& m) noexcept;-?- Constraints: The argument supplied by the caller for the
-6- Effects:months
parameter is not implicitly convertible toyears
.*this = *this + m
. […]constexpr year_month_weekday& operator-=(const months& m) noexcept;-?- Constraints: The argument supplied by the caller for the
-8- Effects:months
parameter is not implicitly convertible toyears
.*this = *this - m
. […]Modify 30.8.16.3 [time.cal.ymwd.nonmembers] as indicated:
constexpr year_month_weekday operator+(const year_month_weekday& ymwd, const months& dm) noexcept;-?- Constraints: The argument supplied by the caller for the
-2- Returns:months
parameter is not implicitly convertible toyears
.(ymwd.year() / ymwd.month() + dm) / ymwd.weekday_indexed()
.constexpr year_month_weekday operator+(const months& dm, const year_month_weekday& ymwd) noexcept;-?- Constraints: The argument supplied by the caller for the
-3- Returns:months
parameter is not implicitly convertible toyears
.ymwd + dm
.constexpr year_month_weekday operator-(const year_month_weekday& ymwd, const months& dm) noexcept;-?- Constraints: The argument supplied by the caller for the
-4- Returns:months
parameter is not implicitly convertible toyears
.ymwd + (-dm)
.Modify 30.8.17.2 [time.cal.ymwdlast.members] as indicated:
constexpr year_month_weekday_last& operator+=(const months& m) noexcept;-?- Constraints: The argument supplied by the caller for the
-2- Effects:months
parameter is not implicitly convertible toyears
.*this = *this + m
. […]constexpr year_month_weekday_last& operator-=(const months& m) noexcept;-?- Constraints: The argument supplied by the caller for the
-4- Effects:months
parameter is not implicitly convertible toyears
.*this = *this - m
. […]Modify 30.8.17.3 [time.cal.ymwdlast.nonmembers] as indicated:
constexpr year_month_weekday_last operator+(const year_month_weekday_last& ymwdl, const months& dm) noexcept;-?- Constraints: The argument supplied by the caller for the
-2- Returns:months
parameter is not implicitly convertible toyears
.(ymwdl.year() / ymwdl.month() + dm) / ymwdl.weekday_last()
.constexpr year_month_weekday_last operator+(const months& dm, const year_month_weekday_last& ymwdl) noexcept;-?- Constraints: The argument supplied by the caller for the
-3- Returns:months
parameter is not implicitly convertible toyears
.ymwdl + dm
.constexpr year_month_weekday_last operator-(const year_month_weekday_last& ymwdl, const months& dm) noexcept;-?- Constraints: The argument supplied by the caller for the
-4- Returns:months
parameter is not implicitly convertible toyears
.ymwdl + (-dm)
.
[2020-02-13, Prague]
Tim Song found a wording problem that we would like to resolve:
Given a class likestruct C : months { operator years(); };
The previous wording requires calls with a C
argument to use the years
overload, which
would require implementation heroics since its conversion sequence to months
is better than years
.
[2020-02 Status to Immediate on Friday morning in Prague.]
Proposed resolution:
This wording is relative to N4849.
[Drafting note: Suggested wording below assumes that we can add a Constraints: to a signature where the constraint does not apply to a deduced template. We have examples of such constraints in other parts of the WD (e.g. 20.3.1.3.2 [unique.ptr.single.ctor]/p15, 20.3.1.3.4 [unique.ptr.single.asgn]/p1). And we have the old form "does not participate …" being used for non-deduced templates in several places as well (e.g. 22.3.2 [pairs.pair]/p5).
There are several ways of implementing such a constraint, such as adding a gratuitous template parameter.]
Modify 30.8.13.2 [time.cal.ym.members] as indicated:
constexpr year_month& operator+=(const months& dm) noexcept;-?- Constraints: If the argument supplied by the caller for the
-4- Effects:months
parameter is convertible toyears
, its implicit conversion sequence toyears
is worse than its implicit conversion sequence tomonths
(12.2.4.3 [over.ics.rank]).*this = *this + dm
. […]constexpr year_month& operator-=(const months& dm) noexcept;-?- Constraints: If the argument supplied by the caller for the
-6- Effects:months
parameter is convertible toyears
, its implicit conversion sequence toyears
is worse than its implicit conversion sequence tomonths
(12.2.4.3 [over.ics.rank]).*this = *this - dm
. […]
Modify 30.8.13.3 [time.cal.ym.nonmembers] as indicated:
constexpr year_month operator+(const year_month& ym, const months& dm) noexcept;-?- Constraints: If the argument supplied by the caller for the
-3- Returns: Amonths
parameter is convertible toyears
, its implicit conversion sequence toyears
is worse than its implicit conversion sequence tomonths
(12.2.4.3 [over.ics.rank]).year_month
valuez
such thatz - ym == dm
. […]constexpr year_month operator+(const months& dm, const year_month& ym) noexcept;-?- Constraints: If the argument supplied by the caller for the
-5- Returns:months
parameter is convertible toyears
, its implicit conversion sequence toyears
is worse than its implicit conversion sequence tomonths
(12.2.4.3 [over.ics.rank]).ym + dm
.constexpr year_month operator-(const year_month& ym, const months& dm) noexcept;-?- Constraints: If the argument supplied by the caller for the
-6- Returns:months
parameter is convertible toyears
, its implicit conversion sequence toyears
is worse than its implicit conversion sequence tomonths
(12.2.4.3 [over.ics.rank]).ym + -dm
.
Modify 30.8.14.2 [time.cal.ymd.members] as indicated:
constexpr year_month_day& operator+=(const months& m) noexcept;-?- Constraints: If the argument supplied by the caller for the
-7- Effects:months
parameter is convertible toyears
, its implicit conversion sequence toyears
is worse than its implicit conversion sequence tomonths
(12.2.4.3 [over.ics.rank]).*this = *this + m
. […]constexpr year_month_day& operator-=(const months& m) noexcept;-?- Constraints: If the argument supplied by the caller for the
-9- Effects:months
parameter is convertible toyears
, its implicit conversion sequence toyears
is worse than its implicit conversion sequence tomonths
(12.2.4.3 [over.ics.rank]).*this = *this - m
. […]
Modify 30.8.14.3 [time.cal.ymd.nonmembers] as indicated:
constexpr year_month_day operator+(const year_month_day& ymd, const months& dm) noexcept;-?- Constraints: If the argument supplied by the caller for the
-3- Returns:months
parameter is convertible toyears
, its implicit conversion sequence toyears
is worse than its implicit conversion sequence tomonths
(12.2.4.3 [over.ics.rank]).(ymd.year() / ymd.month() + dm) / ymd.day()
. […]constexpr year_month_day operator+(const months& dm, const year_month_day& ymd) noexcept;-?- Constraints: If the argument supplied by the caller for the
-5- Returns:months
parameter is convertible toyears
, its implicit conversion sequence toyears
is worse than its implicit conversion sequence tomonths
(12.2.4.3 [over.ics.rank]).ymd + dm
.constexpr year_month_day operator+(const months& dm, const year_month_day& ymd) noexcept;-?- Constraints: If the argument supplied by the caller for the
-6- Returns:months
parameter is convertible toyears
, its implicit conversion sequence toyears
is worse than its implicit conversion sequence tomonths
(12.2.4.3 [over.ics.rank]).ymd + (-dm)
.
Modify 30.8.15.2 [time.cal.ymdlast.members] as indicated:
constexpr year_month_day_last& operator+=(const months& m) noexcept;-?- Constraints: If the argument supplied by the caller for the
-2- Effects:months
parameter is convertible toyears
, its implicit conversion sequence toyears
is worse than its implicit conversion sequence tomonths
(12.2.4.3 [over.ics.rank]).*this = *this + m
. […]constexpr year_month_day_last& operator-=(const months& m) noexcept;-?- Constraints: If the argument supplied by the caller for the
-4- Effects:months
parameter is convertible toyears
, its implicit conversion sequence toyears
is worse than its implicit conversion sequence tomonths
(12.2.4.3 [over.ics.rank]).*this = *this - m
. […]
Modify 30.8.15.3 [time.cal.ymdlast.nonmembers] as indicated:
constexpr year_month_day_last operator+(const year_month_day_last& ymdl, const months& dm) noexcept;-?- Constraints: If the argument supplied by the caller for the
-3- Returns:months
parameter is convertible toyears
, its implicit conversion sequence toyears
is worse than its implicit conversion sequence tomonths
(12.2.4.3 [over.ics.rank]).(ymdl.year() / ymdl.month() + dm) / last
.constexpr year_month_day_last operator+(const months& dm, const year_month_day_last& ymdl) noexcept;-?- Constraints: If the argument supplied by the caller for the
-4- Returns:months
parameter is convertible toyears
, its implicit conversion sequence toyears
is worse than its implicit conversion sequence tomonths
(12.2.4.3 [over.ics.rank]).ymdl + dm
.constexpr year_month_day_last operator-(const year_month_day_last& ymdl, const months& dm) noexcept;-?- Constraints: If the argument supplied by the caller for the
-5- Returns:months
parameter is convertible toyears
, its implicit conversion sequence toyears
is worse than its implicit conversion sequence tomonths
(12.2.4.3 [over.ics.rank]).ymdl + (-dm)
.
Modify 30.8.16.2 [time.cal.ymwd.members] as indicated:
constexpr year_month_weekday& operator+=(const months& m) noexcept;-?- Constraints: If the argument supplied by the caller for the
-6- Effects:months
parameter is convertible toyears
, its implicit conversion sequence toyears
is worse than its implicit conversion sequence tomonths
(12.2.4.3 [over.ics.rank]).*this = *this + m
. […]constexpr year_month_weekday& operator-=(const months& m) noexcept;-?- Constraints: If the argument supplied by the caller for the
-8- Effects:months
parameter is convertible toyears
, its implicit conversion sequence toyears
is worse than its implicit conversion sequence tomonths
(12.2.4.3 [over.ics.rank]).*this = *this - m
. […]
Modify 30.8.16.3 [time.cal.ymwd.nonmembers] as indicated:
constexpr year_month_weekday operator+(const year_month_weekday& ymwd, const months& dm) noexcept;-?- Constraints: If the argument supplied by the caller for the
-2- Returns:months
parameter is convertible toyears
, its implicit conversion sequence toyears
is worse than its implicit conversion sequence tomonths
(12.2.4.3 [over.ics.rank]).(ymwd.year() / ymwd.month() + dm) / ymwd.weekday_indexed()
.constexpr year_month_weekday operator+(const months& dm, const year_month_weekday& ymwd) noexcept;-?- Constraints: If the argument supplied by the caller for the
-3- Returns:months
parameter is convertible toyears
, its implicit conversion sequence toyears
is worse than its implicit conversion sequence tomonths
(12.2.4.3 [over.ics.rank]).ymwd + dm
.constexpr year_month_weekday operator-(const year_month_weekday& ymwd, const months& dm) noexcept;-?- Constraints: If the argument supplied by the caller for the
-4- Returns:months
parameter is convertible toyears
, its implicit conversion sequence toyears
is worse than its implicit conversion sequence tomonths
(12.2.4.3 [over.ics.rank]).ymwd + (-dm)
.
Modify 30.8.17.2 [time.cal.ymwdlast.members] as indicated:
constexpr year_month_weekday_last& operator+=(const months& m) noexcept;-?- Constraints: If the argument supplied by the caller for the
-2- Effects:months
parameter is convertible toyears
, its implicit conversion sequence toyears
is worse than its implicit conversion sequence tomonths
(12.2.4.3 [over.ics.rank]).*this = *this + m
. […]constexpr year_month_weekday_last& operator-=(const months& m) noexcept;-?- Constraints: If the argument supplied by the caller for the
-4- Effects:months
parameter is convertible toyears
, its implicit conversion sequence toyears
is worse than its implicit conversion sequence tomonths
(12.2.4.3 [over.ics.rank]).*this = *this - m
. […]
Modify 30.8.17.3 [time.cal.ymwdlast.nonmembers] as indicated:
constexpr year_month_weekday_last operator+(const year_month_weekday_last& ymwdl, const months& dm) noexcept;-?- Constraints: If the argument supplied by the caller for the
-2- Returns:months
parameter is convertible toyears
, its implicit conversion sequence toyears
is worse than its implicit conversion sequence tomonths
(12.2.4.3 [over.ics.rank]).(ymwdl.year() / ymwdl.month() + dm) / ymwdl.weekday_last()
.constexpr year_month_weekday_last operator+(const months& dm, const year_month_weekday_last& ymwdl) noexcept;-?- Constraints: If the argument supplied by the caller for the
-3- Returns:months
parameter is convertible toyears
, its implicit conversion sequence toyears
is worse than its implicit conversion sequence tomonths
(12.2.4.3 [over.ics.rank]).ymwdl + dm
.constexpr year_month_weekday_last operator-(const year_month_weekday_last& ymwdl, const months& dm) noexcept;-?- Constraints: If the argument supplied by the caller for the
-4- Returns:months
parameter is convertible toyears
, its implicit conversion sequence toyears
is worse than its implicit conversion sequence tomonths
(12.2.4.3 [over.ics.rank]).ymwdl + (-dm)
.