In this section, we will write a little game that prompts the user to enter a specific word. The time that the user needs to type this word into the keyboard is measured and displayed in multiple time units:
- At first, we need to include all the necessary headers. For reasons of comfort, we declare that we use the std namespace by default:
#include <iostream>
#include <chrono>
#include <ratio>
#include <cmath>
#include <iomanip>
#include <optional>
using namespace std;
- The chrono::duration as a type for time durations usually refers to multiples or fractions of seconds. All the STL time duration units refer to integer typed duration specializations. In this recipe, we are going to specialize on double. In the recipe after this one, we will concentrate more on the existing time unit definitions that are already built into the STL:
using seconds = chrono::duration<double>;
- One millisecond is a fraction of a second, so we define this unit by referring to seconds. The ratio_multiply template parameter applies the STL-predefined milli factor to seconds::period, which gives us the fraction we want. The ratio_multiply template is basically a meta programming function for multiplying ratios:
using milliseconds = chrono::duration<
double, ratio_multiply<seconds::period, milli>>;
- It's the same thing with microseconds. While a millisecond is a milli-fraction of a second, a microsecond is a micro-fraction of a second:
using microseconds = chrono::duration<
double, ratio_multiply<seconds::period, micro>>;
- Now we are going to implement a function, which reads a string from user input and measures how long it took the user to type the input. It takes no arguments and returns us the user input string as well as the elapsed time, bundled in a pair:
static pair<string, seconds> get_input()
{
string s;
- We need to take the time from the beginning of the period during which user input occurs and after it. Taking a time snapshot looks like this:
const auto tic (chrono::steady_clock::now());
- The actual capturing of user input takes place now. If we are not successful, we just return a default-initialized tuple. The caller will see that he got an empty input string:
if (!(cin >> s)) {
return {{}, {}};
}
- In the case of success, we continue by taking another time snapshot. Then we return the input string and the difference between both time points. Note that both are absolute time points, but by calculating the difference, we get a duration:
const auto toc (chrono::steady_clock::now());
return {s, toc - tic};
}
- Let's implement the actual program now. We loop until the user enters the input string correctly. In every loop step, we ask the user to please enter the string "C++17" and, then, call our get_input function:
int main()
{
while (true) {
cout << "Please type the word "C++17" as"
" fast as you can.n> ";
const auto [user_input, diff] = get_input();
- Then we check the input. If the input is empty, we interpret this as a request to exit the whole program:
if (user_input == "") { break; }
- If the user correctly types "C++17", we express our congratulations and then print the time the user needed to type the word correctly. The diff.count() method returns the number of seconds as a floating point number. If we had used the original STL seconds duration type, then we would have got a rounded integer value, not a fraction. By feeding the milliseconds or microseconds constructor with our diff variable before calling count(), we get the same value transformed to a different unit:
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;
- If the user has a typo in the input, we let him try again:
} else {
cout << "Sorry, your input does not match."
" You may try again.n";
}
}
}
- Compiling and running the program leads to the following output. At first, with a typo, the program repeatedly asks for the correct input word. After typing the word correctly, it displays how long it took us to type it in three different time units:
$ ./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.