📚 Hub Books: Онлайн-чтение книгРазная литератураC++17 STL Стандартная библиотека шаблонов - Яцек Галовиц

C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц

Шрифт:

-
+

Интервал:

-
+
1 ... 76 77 78 79 80 81 82 83 84 ... 121
Перейти на страницу:
считает входную строку, отправленную пользователем, и определит, сколько времени ему потребовалось для ее ввода. Она не принимает никаких аргументов и возвращает строку, введенную пользователем, а также время, которое ему потребовалось на ввод, упакованные в одну пару:

static pair<string, seconds> get_input()

{

  string s;

6. Нужно получить время, в которое пользователь начал вводить строку, а также время, в которое он это делать закончил. Данная операция выглядит следующим образом:

  const auto tic (chrono::steady_clock::now());

7. Сейчас мы получим данные от пользователя. Если эта операция пройдет безуспешно, то просто вернем кортеж, инициализированный значениями по умолчанию. Вызывающая сторона получит пустую строку:

  if (!(cin >> s)) {

    return {{}, {}};

  }

8. В случае успеха продолжим работу, сделав еще один снимок текущего времени. Далее вернем входную строку и разницу между временными точками. Обратите внимание: обе временные точки выражены в абсолютном виде, но, вычислив их разность, мы получаем длительность:

  const auto toc (chrono::steady_clock::now());

  return {s, toc - tic};

}

9. Теперь реализуем саму программу. Запустим цикл, который будет работать до тех пор, пока пользователь не введет корректную строку. На каждом шаге цикла мы просим пользователя ввести строку "C++17", а затем вызываем функцию get_input:

int main()

{

  while (true) {

    cout << "Please type the word "C++17" as"

            " fast as you can.n> ";

    const auto [user_input, diff] = get_input();

10. Далее проверим входные данные. Если они пусты, то интерпретируем это как запрос на завершение программы:

    if (user_input == "") { break; }

11. Если пользователь корректно введет строку "C++17", то поздравим его, а затем выведем время, которое ему потребовалось на данное действие. Метод diff.count() возвращает количество секунд в качестве числа с плавающей точкой. Используй мы оригинальный тип duration STL seconds, получили бы округленное целочисленное значение, а не дробное. Передавая конструктору milliseconds или microseconds нашу переменную diff перед вызовом count(), получаем то же значение, преобразованное в другую единицу измерения:

    if (user_input == "C++17") {

      cout << "Bravo. You did it in:n"

           << fixed << setprecision(2)

           << setw(12) << diff.count()

           << " seconds.n"

           << setw(12) << milliseconds(diff).count()

           << " milliseconds.n"

           << setw(12) << microseconds(diff).count()

           << " microseconds.n";

      break;

12. Если пользователь сделал опечатку, то позволим ему повторить попытку:

    } else {

      cout << "Sorry, your input does not match."

              " You may try again.n";

    }

  }

}

13. Компиляция и запуск программы дадут следующий результат. Сначала при наличии опечаток программа попросит пользователя ввести корректное слово. После этого она отобразит время, которое потребовалось на то, чтобы ввести его, в трех единицах измерения.

$ ./ratio_conversion

Please type the word "C++17" as fast as you can.

> c+17

Sorry, your input does not match. You may try again.

Please type the word "C++17" as fast as you can.

> C++17

Bravo. You did it in:

      1.48 seconds.

   1480.10 milliseconds.

1480099.00 microseconds.

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

Несмотря на то что этот раздел посвящен выполнению преобразований между разными единицами измерения времени, сначала нужно выбрать один из трех доступных объектов часов. Как правило, в пространстве имен std::chrono можно выбрать между system_clock, steady_clock и high_resolution_clock. Чем они отличаются? Взглянем на их описание (табл. 8.1).

Поскольку мы определяли продолжительность промежутка времени между двумя абсолютными точками во времени (они хранятся в переменных tic и toc), нам не нужно знать, были ли эти точки искажены глобально. Даже если часы спешат или опаздывают на 112 лет 5 часов 10 минут и 1 секунду (или другое значение), это не отражается на разности между ними. Единственное, что важно, — после того, как мы сохраняем временную точку tic, и до того, как сохраняем временную точку toc, для часов нельзя выполнить микронастройку (что случается время от времени во многих системах), поскольку это исказит измерение. Согласно данным требованиям, оптимальным выбором является steady_clock. Их реализация может быть основана на счетчике временных меток процессора, который всегда монотонно увеличивается с момента запуска системы.

О’кей, теперь, когда мы выбрали правильный объект time, можем сохранить временные точки с помощью функции chrono::steady_clock::now(). Функция now возвращает значение типа chrono::time_point<chrono::steady_clock>. Разность между двумя такими значениями (toc–tic) является временным промежутком, или продолжительностью, имеющей тип chrono::duration.

Поскольку данный тип является основным для текущего раздела, все немного усложняется. Рассмотрим интерфейс шаблонного типа duration более пристально:

template<

  class Rep,

  class Period = std::ratio<1>

> class duration;

Можно изменить значения параметров Rep и Period. Значение параметра Rep объяснить легко: это всего лишь численный тип переменной, который используется для сохранения значения времени. Для существующих в STL единиц измерения времени таковым обычно выступает тип long long int. В данном примере мы выбрали тип double и благодаря этому можем сохранять по умолчанию значения в секундах, а затем преобразовывать их в милли- или микросекунды. Если у нас есть промежуток времени, равный 1.2345 секунды и имеющий тип chrono::seconds, то значение будет округлено до одной целой секунды. Таким образом, нужно сохранить разность между переменными tic и toc в переменной типа chrono::microseconds, а затем преобразовать его в менее точные единицы. Из-за выбора типа double для Rep можно выполнять преобразование к более и менее точным единицам и терять минимальный объем точности, что не влияет на наш пример.

Мы использовали Rep = double для всех единиц измерения времени, поэтому они отличаются значением параметра Period:

using seconds = chrono::duration<double>;

using milliseconds = chrono::duration<double,

  ratio_multiply<seconds::period, milli>>;

using microseconds = chrono::duration<double,

  ratio_multiply<seconds::period, micro>>;

Секунды — самая простая в описании единица времени, поскольку можно воспользоваться

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

Комментарии

Обратите внимание, что комментарий должен быть не короче 20 символов. Покажите уважение к себе и другим пользователям!

Никто еще не прокомментировал. Хотите быть первым, кто выскажется?