• Class / Function / Type

      std::
    • Header file

      <>
    • Other / All

    最終更新日時(UTC):
    が更新

    履歴 編集

    class template
    <type_traits>

    std::underlying_type

    namespace std {
      template <class T>
      struct underlying_type {
        using type = ;
      };
    
      template <class T>
      using underlying_type_t = typename underlying_type<T>::type; // C++14
    }
    

    概要

    列挙型の基底型を取得する。

    C++11以降の列挙型(enumenum classenum structで定義された型)は、列挙子の値を表現するための基底型を指定できる:

    // 基底型にcharを指定。
    // 列挙子の値を表現するためにcharが使用される。
    enum class CharColor : char {
      Red, Green, Blue
    };
    
    // 基底型を指定しない場合、
    // enum classではintがデフォルトの基底型となる。
    enum class IntColor {
      Red, Green Blue
    };
    

    underlying_typeを使用することで、列挙型に設定された基底型を取得できる。

    要件

    • C++11 : 型Tが列挙型であること。(完全型を要求するかどうかは未規定)
    • C++14 : 型Tが完全な列挙型であること。
    • C++20 : 型Tが不完全な列挙型ではないこと。(満たさない場合不適格)

    効果

    underlying_typeは、列挙型Tの基底型を、メンバ型typeとして定義する。

    C++20からはTが列挙型ではない場合、typeは定義されない。 これによりSFINAEの文脈で使うときにこれまで不適格となるために列挙型以外の型のときに実体化を防ぐ必要があったところをその必要がなくなった。

    #include <type_traits>
    /**
    Tが列挙型ではないときも、std::underlying_type_t<T>が実体化してしまっているため不適格
    template<class T>
    std::enable_if_t<std::is_enum<T>::value, std::underlying_type_t<T>>
    foo(T t) { return static_cast<underlying_type_wrap_t<T>>(t); }
    */
    #if 1
    // p0340r3が適用されていない処理系
    template<typename T, bool is_enum>
    struct underlying_type_wrap_impl {};
    template<typename T>
    struct underlying_type_wrap_impl<T, true> : std::underlying_type<T> {};//列挙型に対する特殊化なのでOK
    template<typename T>
    struct underlying_type_wrap : underlying_type_wrap_impl<T, std::is_enum<T>::value> {};
    template<typename T>
    using underlying_type_wrap_t = typename underlying_type_wrap<T>::type;
    
    template<typename T>
    underlying_type_wrap_t<T> foo(T t) { return static_cast<underlying_type_wrap_t<T>>(t); }
    #else
    // C++20またはp0340r3が適用された処理系
    // => 上のようなラッパーはいらない
    template<typename T>
    std::underlying_type_t<T> foo(T t) { return static_cast<std::underlying_type_t<T>>(t); }
    #endif
    template<typename T, std::enable_if_t<std::is_integral<T>::value, std::nullptr_t> = nullptr>
    T foo(T t) { return t; }
    enum class bar {
        hoge
    };
    int main(){
        return foo(bar::hoge) + foo(0);
    }
    

    #include <type_traits>
    
    enum E1 : char {};
    enum class E2 : char {};
    
    enum E3 {};
    enum class E4 {};
    
    static_assert(std::is_same<std::underlying_type<E1>::type, char>::value, "E1 based type is char");
    static_assert(std::is_same<std::underlying_type<E2>::type, char>::value, "E2 based type is char");
    
    static_assert(std::is_integral<std::underlying_type<E3>::type>::value == true, "E3 based type is integral type");
    static_assert(std::is_integral<std::underlying_type<E4>::type>::value == true, "E4 based type is integral type");
    
    int main() {}
    

    出力

    バージョン

    言語

    • C++11

    処理系

    underlying_type

    P0340R3: Making std::underlying_type SFINAE-friendly

    以下の処理系ではコンパイル時の言語バージョンスイッチに関わらずP0340R3の修正が適用されている

    関連項目

    参照