**Section:** 29.5.2 [time.duration.cons] **Status:** New
**Submitter:** Richard Smith **Opened:** 2018-03-22 **Last modified:** 2020-09-12 11:59:20 UTC

**Priority: **3

**View all other** issues in [time.duration.cons].

**View all issues with** New status.

**Discussion:**

29.5.2 [time.duration.cons] p4 says:

template<class Rep2, class Period2> constexpr duration(const duration<Rep2, Period2>& d);

Remarks:This constructor shall not participate in overload resolution unless no overflow is induced in the conversion andtreat_as_floating_point_v<rep>istrueor bothratio_divide<Period2, period>::denis 1 andtreat_as_floating_point_v<Rep2>isfalse.

with this example:

duration<int, milli> ms(3); duration<int, micro> us = ms;// OKduration<int, milli> ms2 = us;// error

It's unclear to me what "no overflow is induced in the conversion" means in the above. What happens here:

duration<int, milli> ms(INT_MAX); duration<int, micro> us = ms;// ???

An overflow is clearly induced in the conversion here: internally, we'll multiply `INT_MAX` by 1000. But that
cannot be determined statically (in general), and so can't affect the result of overload resolution.

So what's actually supposed to happen? Are we actually just supposed to check that `Rep2` is no larger than `Rep`?
(If so, what happens on overflow? Undefined behavior?)

It has been pointed out by Howard Hinnant:

This refers to the compile-time conversion factor to convertPeriod2toPeriod. If that conversion factor is not representable as a (reduced)ratio<N, D>, then the constructor is SFINAE'd out. This might happen (for example) converting years to picoseconds.

I would not have guessed that from the wording. Maybe replacing "no overflow is induced in the conversion" with "the result
of `ratio_divide<Period2, Period>` is representable as a `ratio`" or similar would help?

*[2018-06-18 after reflector discussion]*

Priority set to 3

*[2020-09-12 Jonathan adds a proposed resolution]*

Since the result of the `ratio_divide` has to be a `ratio`,
if it's not representable then the result simply isn't a valid type.
Implementations are not required to make `ratio_divide` SFINAE-friendly
to implement this constraint. They can perform the equivalent calculations
to check if they would overflow, without actually using `ratio_divide`.

**Proposed resolution:**

This wording is relative to N4861.

Modify 29.5.2 [time.duration.cons] as indicated:

template<class Rep2, class Period2> constexpr duration(const duration<Rep2, Period2>& d);

-3-

*Constraints:*`is_convertible_v<const Rep2&, rep>`is`true`.`ratio_divide<typename Period2::type, period>`is a valid`ratio`specialization. Either:-
`treat_as_floating_point_v<rep>`is`true`; or -
`ratio_divide<Period2, period>::den`is`1`and`treat_as_floating_point_v<Rep2>`is`false`.

~~No overflow is induced in the conversion and~~[`treat_as_floating_point_v<rep>`is`true`or both`ratio_divide<Period2, period>::den`is`1`and`treat_as_floating_point_v<Rep2>`is`false`.*Note:*This requirement prevents implicit truncation errors when converting between integral-based`duration`types. Such a construction could easily lead to confusion about the value of the`duration`. —*end note*]-