This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of NAD status.
Section: 30.3 [time.clock.req] Status: NAD Submitter: Pete Becker Opened: 2009-01-07 Last modified: 2016-01-28
Priority: Not Prioritized
View all other issues in [time.clock.req].
View all issues with NAD status.
Discussion:
30.3 [time.clock.req] requires that a clock type have a member
typedef named time_point
that names an instantiation of the
template time_point
, and a member named duration
that
names an instantiation of the template duration
. This mixing of
levels is confusing. The typedef names should be different from the
template names.
[ Post Summit, Anthony provided proposed wording. ]
[ 2009-05-04 Howard adds: ]
The reason that the typedef names were given the same name as the class templates was so that clients would not have to stop and think about whether they were using the clock's native
time_point
/duration
or the class template directly. In this case, one person's confusion is another person's encapsulation. The detail that sometimes one is referring to the clock's native types, and sometimes one is referring to an independent type is purposefully "hidden" because it is supposed to be an unimportant detail. It can be confusing to have to remember when to typeduration
and when to typeduration_type
, and there is no need to require the client to remember something like that.For example, here is code that I once wrote in testing out the usability of this facility:
template <class Clock, class Duration> void do_until(const std::chrono::time_point<Clock, Duration>& t) { typename Clock::time_point now = Clock::now(); if (t > now) { typedef typename std::common_type < Duration, typename std::chrono::system_clock::duration >::type CD; typedef std::chrono::duration<double, std::nano> ID; CD d = t - now; ID us = duration_cast<ID>(d); if (us < d) ++us; ... } }I see no rationale to require the client to append
_type
to some of those declarations. It seems overly burdensome on the author ofdo_until
:template <class Clock, class Duration> void do_until(const std::chrono::time_point<Clock, Duration>& t) { typename Clock::time_point_type now = Clock::now(); if (t > now) { typedef typename std::common_type < Duration, typename std::chrono::system_clock::duration_type >::type CD; typedef std::chrono::duration<double, std::nano> ID; CD d = t - now; ID us = duration_cast<ID>(d); if (us < d) ++us; ... } }Additionally I'm fairly certain that this suggestion hasn't been implemented. If it had, it would have been discovered that it is incomplete.
time_point
also has a nested type (purposefully) namedduration
.That is, the current proposed wording would put the WP into an inconsistent state.
In contrast, the current WP has been implemented and I've received very favorable feedback from people using this interface in real-world code.
[ Batavia (2009-05): ]
Bill agrees that distinct names should be used for distinct kinds of entities.
Walter would prefer not to suffix type names, especially for such well-understood terms as "duration".
Howard reminds us that the proposed resolution is incomplete, per his comment in the issue.
Move to Open.
[ 2009-06-07 Howard adds: ]
Not meaning to be argumentative, but we have a decade of positive experience with the precedent of using the same name for the nested type as an external class representing an identical concept.
template<class Category, class T, class Distance = ptrdiff_t, class Pointer = T*, class Reference = T&> struct iterator { ... }; template <BidirectionalIterator Iter> class reverse_iterator { ... }; template <ValueType T, Allocator Alloc = allocator<T> > requires NothrowDestructible<T> class list { public: typedef implementation-defined iterator; ... typedef reverse_iterator<iterator> reverse_iterator; ... };I am aware of zero complaints regarding the use of
iterator
andreverse_iterator
as nested types of the containers despite these names also having related meaning at namespace std scope.Would we really be doing programmers a favor by renaming these nested types?
template <ValueType T, Allocator Alloc = allocator<T> > requires NothrowDestructible<T> class list { public: typedef implementation-defined iterator_type; ... typedef reverse_iterator<iterator> reverse_iterator_type; ... };I submit that such design contributes to needless verbosity which ends up reducing readability.
[ 2009-10 Santa Cruz: ]
Mark as NAD. No concensus for changing the WP.
Proposed resolution:
Change 30 [time]:
... template <class Clock, class Duration = typename Clock::duration_type> class time_point; ...
Change 30.3 [time.clock.req]:
Table 45 -- Clock requirements Expression Return type Operational semantics ... ... ... C1::duration_type
chrono::duration<C1::rep, C1::period>
The native duration
type of the clock.C1::time_point_type
chrono::time_point<C1>
orchrono::time_point<C2, C1::duration_type<
The native time_point
type of the clock. Different clocks may share atime_point_type
definition if it is valid to compare theirtime_point_type
s by comparing their respectiveduration_type
s.C1
andC2
shall refer to the same epoch.... ... ... C1::now()
C1::time_point_type
Returns a time_point_type
object representing the current point in time.
Change 30.7.2 [time.clock.system]:
-1- Objects of class
system_clock
represent wall clock time from the system-wide realtime clock.class system_clock { public: typedef see below rep; typedef ratio<unspecified, unspecified> period; typedef chrono::duration<rep, period> duration_type; typedef chrono::time_point<system_clock> time_point_type; static const bool is_monotonic = unspecified ; static time_point_type now(); // Map to C API static time_t to_time_t (const time_point_type& t); static time_point_type from_time_t(time_t t); };-2-
system_clock::duration_type::min() < system_clock::duration_type::zero()
shall betrue
.time_t to_time_t(const time_point_type& t);-3- Returns: A
time_t
object that represents the same point in time ast
when both values are truncated to the coarser of the precisions oftime_t
andtime_point_type
.time_point_type
from_time_t(time_t t);-4- Returns: A
time_point_type
object that represents the same point in time ast
when both values are truncated to the coarser of the precisions oftime_t
andtime_point_type
.
Change 99 [time.clock.monotonic]:
class monotonic_clock { public: typedef unspecified rep; typedef ratio<unspecified , unspecified> period; typedef chrono::duration<rep, period> duration_type; typedef chrono::time_point<unspecified , duration_type> time_point_type; static const bool is_monotonic = true; static time_point_type now(); };
Change 30.7.8 [time.clock.hires]:
class high_resolution_clock { public: typedef unspecified rep; typedef ratio<unspecified , unspecified> period; typedef chrono::duration<rep, period> duration_type; typedef chrono::time_point<unspecified , duration_type> time_point_type; static const bool is_monotonic = true; static time_point_type now(); };