chitay-knigi.com » Разная литература » C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 77 78 79 80 81 82 83 84 85 ... 121
Перейти на страницу:
конструкцией Period = ratio<1>, другие же придется подстраивать. Поскольку миллисекунда — одна тысячная секунды, мы умножим seconds::period (который представляет собой всего лишь функцию-геттер для параметра Period) на milli — псевдоним типа std::ratio<1, 1000> (std::ratio<a, b> — это дробное значение a/b). Тип ratio_multiply, по сути, является функцией времени компиляции, которая представляет собой тип, получаемый в результате умножения одного типа ratio на другой.

Это может показаться непонятным, так что рассмотрим пример: команда ratio_multiply<ratio<2, 3>, ratio<4, 5>> даст результат ratio<8, 15>, поскольку (2/3) * (4/5) = 8/15.

Полученные описания типов эквивалентны следующим описаниям:

using seconds      = chrono::duration<double, ratio<1, 1>>;

using milliseconds = chrono::duration<double, ratio<1, 1000>>;

using microseconds = chrono::duration<double, ratio<1, 1000000>>;

После получения этих типов можно легко выполнять преобразования между ними. При наличии промежутка времени d с типом seconds можно преобразовать его в тип milliseconds, передав в конструктор другого типа — milliseconds(d).

Дополнительная информация

В других учебниках и книгах при преобразовании промежутков времени вы могли столкнуться с duration_cast. Если у нас есть промежуток времени типа chrono::milliseconds и нужно преобразовать его к типу chrono::hours, например, то следует написать конструкцию duration_cast<chrono::hours>(milliseconds_value), поскольку данные единицы измерения зависят от целочисленных типов. Преобразование точных единиц времени в менее точные приводит к потере точности, именно поэтому и нужен duration_cast. Для продолжительностей, основанных на типах double или float, этого не требуется.

Выполняем преобразование между абсолютными и относительными значениями с использованием std::chrono

До C++11 было довольно сложно получить физическое время и просто вывести его на экран, поскольку C++ не имела собственной библиотеки для работы с временем. Требовалось всегда вызывать функции библиотеки С, которая выглядит очень архаично, учитывая, что такие вызовы могут быть инкапсулированы в собственные классы.

Начиная с C++11, в STL можно найти библиотеку chrono, она значительно упрощает решение задач, связанных с временем.

В этом примере мы возьмем местное время, выведем его на экран и поработаем с ним, добавляя разные смещения, что очень удобно делать с помощью библиотеки std::chrono.

Как это делается

В примере мы сохраним текущее время и выведем его на экран. Кроме того, наша программа будет добавлять разные смещения к сохраненному времени и выводить на экран полученные результаты.

1. Сначала идут типичные директивы include, затем мы объявляем об использовании по умолчанию пространства имен std:

#include <iostream>

#include <iomanip>

#include <chrono>

using namespace std;

2. Выведем на экран абсолютные моменты времени. Они будут иметь форму шаблона типа chrono::time_point, поэтому просто перегрузим для него оператор выходного потока. Существуют разные способы вывести на экран дату и/или время для заданного момента. Мы применим только стандартное форматирование %c. Можно было бы, конечно, также вывести только время, только дату, только год или что-то еще, приходящее на ум. Все преобразования между разными типами до того, как мы сможем использовать put_time, будут выглядеть несколько «неаккуратно», но мы провернем это лишь однажды.

ostream& operator<<(ostream &os,

         const chrono::time_point<chrono::system_clock> &t)

{

  const auto tt (chrono::system_clock::to_time_t(t));

  const auto loct (std::localtime(&tt));

  return os << put_time(loct, "%c");

}

3. Для секунд, минут, часов и т.д. в STL существуют описания типов. Сейчас мы добавим тип days. Это делается легко; нужно лишь специализировать шаблон chrono::duration, сославшись на часы и умножив их на 24, поскольку сутки насчитывают 24 часа.

using days = chrono::duration<

  chrono::hours::rep,

  ratio_multiply<chrono::hours::period, ratio<24>>>;

4. Чтобы наиболее элегантным способом выразить продолжительность длиной в несколько дней, можно определить собственный пользовательский литерал days. Теперь можно написать 3_days, чтобы создать значение, которое представляет собой три дня.

constexpr days operator ""_days(unsigned long long h)

{

  return days{h};

}

5. В самой программе сделаем снимок момента времени, который затем просто выведем на экран. Это очень легко и удобно, поскольку мы уже реализовали правильную версию перегруженного оператора.

int main()

{

  auto now (chrono::system_clock::now());

  cout << "The current date and time is " << now << 'n';

6. Сохранив текущее время в переменной now, можем добавить к нему произвольные продолжительности и также вывести их на экран. Добавим к текущему времени 12 часов и выведем результат на экран:

  chrono::hours chrono_12h {12};

  cout << "In 12 hours, it will be "

       << (now + chrono_12h)<< 'n';

7. Объявляя об использовании по умолчанию пространства имен chrono_literals, разблокируем все существующие литералы, описывающие продолжительность, для часов, секунд и т.д. Таким образом, можно изящно вывести на экран, какое время было 12 часов 15 минут назад или семь дней назад.

  using namespace chrono_literals;

  cout << "12 hours and 15 minutes ago, it was "

       << (now - 12h - 15min) << 'n'

       << "1 week ago, it was "

       << (now - 7_days) << 'n';

}

8. Компиляция и запуск программы дадут следующий результат. Поскольку мы использовали в качестве строки форматирования %c, получим довольно полное описание в конкретном формате. Поработав с разными строками формата, можем вывести время в любом формате, который нам нравится. Обратите внимание: здесь мы применяем 24-часовой формат.

$ ./relative_absolute_times

The current date and time is Fri May 5 13:20:38 2017

In 12 hours, it will be Sat May 6 01:20:38 2017

12 hours and 15 minutes ago, it was Fri May 5 01:05:38 2017

1 week ago, it was Fri Apr 28 13:20:38 2017

Как это работает

Мы получили текущий момент времени из std::chrono::system_clock. Этот класс часов STL единственный способен преобразовывать свои значения моментов времени в структуру time, которая может быть отображена в виде понятной человеку строки описания.

Чтобы вывести на экран такие моменты времени, мы реализовали оператор << для потока вывода:

ostream& operator<<(ostream &os,

       const chrono::time_point<chrono::system_clock> &t)

{

  const auto tt (chrono::system_clock::to_time_t(t));

  const auto loct (std::localtime(&tt));

  return os << put_time(loct, "%c");

}

1 ... 77 78 79 80 81 82 83 84 85 ... 121
Перейти на страницу:

Комментарии
Минимальная длина комментария - 25 символов.
Комментариев еще нет. Будьте первым.