便利なstd::chronoのリテラル演算子

C++11以降、STLを使っているだけでもstd::chronoの時間単位の値が必要になることは多いと思います。その時、整数をそのまま指定出来たらいいのですがそれはできません(std::chrono::durationのコンストラクタがexplicit指定されているため)。仕方ないので、typedefされた各時間単位のコンストラクタを明示的に通すことになります。

auto sec = std::chrono::seconds{2};
auto msec = std::chrono::milliseconds{500};
auto usec = std::chrono::microseconds{500};

//どこからか貰ってきたfutureオブジェクト
future.wait_for(msec);
//もしくは直接
future.wait_for(std::chrono::seconds{5});

こんな感じになるでしょう。最初のうちはこれでいいですが、色んな所で何回もこんな感じの渡し方をするうちに嫌になってくるでしょう・・・。usingしてあげればマシにはなりますがあまりいい感じにはなりません(個人の感想です)。

そこで、C++14よりdurationクラスに追加されているリテラル演算子を使ってみると・・・

using namespace std::literals::chrono_literals;

auto sec = 2s;
auto msec = 500ms;
auto usec = 500us;

//直接与えるときも
future.wait_for(5s);

it's so cool! すごくすっきりしてとても見やすくなりました。しかも意味が明快です。これを知ってしまうともはや今までの書き方には戻れません。ちなみに、このリテラルナノ秒~時間(hour)まで定義されていて、すべてconstexpr指定されています。

using namespace std::literals::chrono_literals;

constexpr auto hour = 12h;
constexpr auto min = 2min;
constexpr auto sec = 2s;
constexpr auto msec = 500ms;
constexpr auto usec = 500us;
constexpr auto nano = 500ns;

いいことずくめに見えますが、std::literals::chrono_literals名前空間をusingしておかなければ使えません。using namespaceは名前空間スコープか関数スコープでしかできないので、名前空間汚染を避けるならば関数毎に先頭でusing namespace std::literals::chrono_literalsするしかないでしょう。これもこれで地味に面倒・・・。他にも、std::chrono_literals、std::literals名前空間のusingでも利用することができます。

このようなリテラルSTL中に他にも、文字列(s)、複素数(i, if, il)などがあるようです。ちなみにこの機能はユーザー定義リテラルと言うのですが、本当にユーザーが定義しようとすると予約語の都合でサフィックス名の先頭にアンダースコア(_)を付けなければなりません、ずるい。

参考文献
hリテラル - cpprefjp C++日本語リファレンス
minリテラル - cpprefjp C++日本語リファレンス
sリテラル - cpprefjp C++日本語リファレンス
msリテラル - cpprefjp C++日本語リファレンス
usリテラル - cpprefjp C++日本語リファレンス
nsリテラル - cpprefjp C++日本語リファレンス
ユーザー定義リテラル - cpprefjp C++日本語リファレンス