This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++20 status.

### 3294. `zoned_time` deduction guides misinterprets `string`/`char*`

Section: 27.11.7.1 [time.zone.zonedtime.overview] Status: C++20 Submitter: Tomasz Kamiński Opened: 2019-09-14 Last modified: 2021-02-25

Priority: 0

View all other issues in [time.zone.zonedtime.overview].

View all issues with C++20 status.

Discussion:

The current deduction guide for `zoned_time` for the following declarations

>     zoned_time zpc("America/New_York", std::chrono::system_clock::now());
>     zoned_time zps(std::string("America/New_York"), std::chrono::system_clock::now());

will attempt to produce a `zoned_time` instance with `const char*` (for `zpc`) and with `std::string` (for `zps`), respectively, as the deduced type for the `TimeZonePtr` template parameter. This is caused by the fact that the unconstrained `TimeZonePtr` deduction guide template will produce better candidates and will be selected by overload resolution.

The proposed resolution merges the deduction of the `std::string_view`/`TimeZonePtr` deduction guides into one guide, that deduces `const time_zone*` for any type convertible to `string_view`. This is necessary to override the deduction from `TimeZonePtr` constructor candidates.

In addition, we disable the deduction from `string_view` constructors, that would produce better candidates than the deduction guides and create `zoned_time` instances with durations coarser than `seconds` (causing similar issue as LWG 3232):

>     std::chrono::local_time<hours> lh(10h);
>     std::chrono::zoned_time zt1("Europe/Helsinki", lh);
>     std::chrono::zoned_time zt2(std::string("Europe/Helsinki"), lh);
>     std::chrono::zoned_time zt3(std::string_view("Europe/Helsinki"), lh);

Without disabling the deduction from the `string_view` constructor, the type of the `zt3` variable would be deduced to `zoned_time<hours>`, with the proposed change the types of the variables `zt1`, `zt2`, and `zt3` are consistently deduced as `zoned_time<seconds>`.

Finally, the wording eliminates the unnecessary `zoned_time<Duration>` guide (covered by `zoned_time<Duration, TimeZonePtr2>`).

The change was implemented in the example implementation. The dedicated test can be found here.

[2019-10-31 Issue Prioritization]

Status to Tentatively Ready and priority to 0 after five positive votes on the reflector.

Proposed resolution:

This wording is relative to N4830.

1. Modify 27.11.7.1 [time.zone.zonedtime.overview], class template `zoned_time` synopsis, as indicated:

   > >     namespace std::chrono {
   > >       […]
   > >       zoned_time() -> zoned_time<seconds>;

   > >       template<class Duration>
   > >         zoned_time(sys_time<Duration>)
   > >           -> zoned_time<common_type_t<Duration, seconds>>;

   > >       template<class TimeZonePtrOrName>
   > >         using time-zone-representation =
   > >           conditional_t<is_convertible_v<TimeZonePtrOrName, string_view>,
   > >             const time_zone*,
   > >             remove_cv_ref<TimeZonePtrOrName>>; // exposition only

   > >       template<class TimeZonePtrOrName>
   > >         zoned_time(TimeZonePtrOrName&&)
   > >           -> zoned_time<seconds, time-zone-representation<TimeZonePtr>>;

   > >       template<class TimeZonePtrOrName, class Duration>
   > >         zoned_time(TimeZonePtrOrName&&, sys_time<Duration>)
   > >           -> zoned_time<common_type_t<Duration, seconds>,
   > >             time-zone-representation<TimeZonePtrOrName>>;

   > >       template<class TimeZonePtrOrName, class Duration>
   > >         zoned_time(TimeZonePtrOrName&&, local_time<Duration>, choose = choose::earliest)
   > >           -> zoned_time<common_type_t<Duration, seconds>,
   > >             time-zone-representation<TimeZonePtrOrName>>;

   > >       template<class TimeZonePtr, class Duration>
   > >         zoned_time(TimeZonePtr, zoned_time<Duration>, choose = choose::earliest)
   > >           ->> zoned_time<common_type_t<Duration, seconds>, TimeZonePtr>;

   > >       zoned_time(string_view) -> zoned_time<seconds>;

   > >       template<class Duration>
   > >         zoned_time(string_view, sys_time<Duration>)
   > >           -> zoned_time<common_type_t<Duration, seconds>>;

   > >       template<class Duration>
   > >         zoned_time(string_view, local_time<Duration>, choose = choose::earliest)
   > >           -> zoned_time<common_type_t<Duration, seconds>>;

   > >       template<class Duration, class TimeZonePtrOrName, class TimeZonePtr2>
   > >         zoned_time(TimeZonePtrOrName&&, zoned_time<Duration, TimeZonePtr2>, choose = choose::earliest)
   > >          -> zoned_time<Duration, time-zone-representation<TimeZonePtrOrName>>;
   > >     }

   > -1- `zoned_time` represents a logical pairing of a `time_zone` and a `time_point` with precision `Duration`. `zoned_time<Duration>` maintains the invariant that it always refers to a valid time zone and represents a point in time that exists and is not ambiguous in that time zone.

   > -2- If `Duration` is not a specialization of `chrono::duration`, the program is ill-formed.

   > -?- Every constructor of `zoned_time` that accepts a `string_view` as first parameter does not participate in class template argument deduction (12.2.2.9 [over.match.class.deduct]).