potisanのプログラミングメモ

趣味のプログラマーがプログラミング関係で気になったことや調べたことをいつでも忘れられるようにメモするブログです。はてなブログ無料版なので記事の上の方はたぶん広告です。記事中にも広告挿入されるみたいです。

C++11 整数→整数の2進接頭辞バイト単位リテラルの定義

C++11から導入されたユーザー定義リテラル(cpprefjp)を使用すると2進接頭辞バイト単位リテラルKiB等)を定義できます。

1KiB1024に変換するような整数型への変換は次のように書けます。

constexpr unsigned long long operator""KiB(unsigned long long value) noexcept {
    return value << 10;
}
constexpr unsigned long long operator""MiB(unsigned long long value) noexcept {
    return value << 20;
}
constexpr unsigned long long operator""GiB(unsigned long long value) noexcept {
    return value << 30;
}
constexpr unsigned long long operator""TiB(unsigned long long value) noexcept {
    return value << 40;
}
constexpr unsigned long long operator""PiB(unsigned long long value) noexcept {
    return value << 50;
}
constexpr unsigned long long operator""EiB(unsigned long long value) noexcept {
    return value << 60;
}
  • ZiB以上(270以上)の単位は1ZiBunsigned long longの範囲を超えるので定義していません。
  • ユーザー定義リテラル_から開始することが推奨されるため、警告C4455「先頭がアンダースコアではないリテラル サフィックス識別子は予約されています」が発生します。
  • C++11以前は""サフィックスの間に空白を入れてoperator"" KiBのように表記する必要があります。C++17以降はoperator""KiBのように表記可能(`""サフィックス間の空白が省略可能)です。
  • constexprおよびnoexceptは削除可能です。

サンプルコードは以下の通りです。C++標準ライブラリに準拠して名前空間で囲っています。

namespace byte_size_literals
{
    constexpr unsigned long long operator""KiB(unsigned long long value) noexcept {
        return value << 10;
    }
    constexpr unsigned long long operator""MiB(unsigned long long value) noexcept {
        return value << 20;
    }
    constexpr unsigned long long operator""GiB(unsigned long long value) noexcept {
        return value << 30;
    }
    constexpr unsigned long long operator""TiB(unsigned long long value) noexcept {
        return value << 40;
    }
    constexpr unsigned long long operator""PiB(unsigned long long value) noexcept {
        return value << 50;
    }
    constexpr unsigned long long operator""EiB(unsigned long long value) noexcept {
        return value << 60;
    }
}

#include <iostream>

int main()
{
    using namespace byte_size_literals;

    std::wcout << 1KiB << std::endl;
    std::wcout << 1MiB << std::endl;
    std::wcout << 1GiB << std::endl;
    std::wcout << 1TiB << std::endl;
    std::wcout << 1PiB << std::endl;
    std::wcout << 1EiB << std::endl;
    // 1024
    // 1048576
    // 1073741824
    // 1099511627776
    // 1125899906842624
    // 1152921504606846976
}