std::underlying_type を使った便利関数

<type_traits>で定義されているテンプレートの1つに std::underlying_type があります。std::underlying_type は、enum型のベースとなっている整数型を取得するためのテンプレート型です。
この std::underlying_type を使うことで、enum を安全に整数型にキャストすることができます。


以下の例では、int型では表せない enum class型が定義されています。これを整数型に変換するには注意を要します。
#include <cstdint>
#include <iostream>

// Enum::LARGEはint型では表せない
enum class Enum : std::uint64_t
{
    LARGE = 0xFFFFFFFFFFFFFFFF
};

int main(void)
{
    // enum classは型に対して厳密なので、暗黙の内の変換はできない
    std::cout << Enum::LARGE << std::endl; // コンパイルエラー!

    // intへの誤変換
    std::cout << static_cast<int>(Enum::LARGE); // => "-1"

    // 正しい変換
    // しかし、enumのベース型を意識する必要がある
    std::cout << static_cast<std::uint64_t>(Enum::LARGE); // => "18446744073709551615"

    return 0;
}
std::underlying_type で enum のベース型を取得できるので、簡単な関数を一つ定義することで、どのような enum であっても、安全に整数型に変換することができます。
関数の実装例は以下のようになります。
#include <cstdint>
#include <iostream>
#include <type_traits>

// enum型をベースの整数型へ変換する関数 e2i()
template <typename ENUM>
typename std::underlying_type<ENUM>::type e2i(ENUM e)
{
    static_assert(std::is_enum<ENUM>::value, "e2i() requires enum argument"); // for safety
    return static_cast<typename std::underlying_type<ENUM>::type>(e);
}

// Enum::LARGEはint型では表せない
enum class Enum : std::uint64_t
{
    LARGE = 0xFFFFFFFFFFFFFFFF
};

int main(void)
{
    // ベース型を意識せずに整数型へ変換可能
    std::cout << e2i(Enum::LARGE) << // => "18446744073709551615"

    return 0;
}

0 件のコメント:

コメントを投稿