代码之家  ›  专栏  ›  技术社区  ›  sergej

如何重用不同类型的运算符重载?

  •  0
  • sergej  · 技术社区  · 7 年前

    我有几个 enums 定义如下:

    enum class Suit {
        spades = 1, hearts, diamonds, clubs,
        first = spades, last = clubs
    };
    
    enum class Rank {
        six = 6, seven, eight, nine, ten, jack, queen, king, ace,
        first = six, last = ace
    };
    

    对于每一个 枚举 我超载了一些操作员:

    Suit operator++(Suit& r) { return r = (Suit)(static_cast<std::underlying_type_t<Suit>>(r) + 1); }
    Rank operator++(Rank& r) { return r = (Rank)(static_cast<std::underlying_type_t<Rank>>(r) + 1); }
    // more overloads ...
    

    注意,两种类型的运算符重载实现是相同的。 如何避免这种代码重复?

    我可以使用模板…

    template<class T>
    T operator++(T& r) { return r = (T)(static_cast<std::underlying_type_t<T>>(r) + 1); }
    

    但是这些重载应该只应用于我的自定义类型。

    2 回复  |  直到 7 年前
        1
  •  2
  •   sergej    7 年前

    下面介绍如何以可伸缩的方式限制模板。

    #include <type_traits>
    
    template <class> 
    constexpr bool is_my_enum = false;       // most types are not my enums
    
    enum class Suit {
        spades = 1, hearts, diamonds, clubs,
        first = spades, last = clubs
    };
    template<> 
    constexpr bool is_my_enum<Suit> = true;  // this is my enum
    
    enum class Rank {
        six = 6, seven, eight, nine, ten, jack, queen, king, ace,
        first = six, last = ace
    };
    template<> 
    constexpr bool is_my_enum<Rank> = true;  // this one is mine too
    
    enum class Moo { moo = 0 };              // but this one isn't
    
    
    
    // define functions for my enums only
    template<class T>
    using for_my_enums = std::enable_if_t<is_my_enum<T>, T>;
    
    template<class T> 
    for_my_enums<T>                        
    operator++(T& r) {return r = (T)(static_cast<std::underlying_type_t<T>>(r) + 1);}
    
    template<class T> 
    for_my_enums<T>                        
    operator++(T& r, int) { 
        auto k = r; 
        r = (T)(static_cast<std::underlying_type_t<T>>(r) + 1); 
        return k;
    }
    
    // ... more functions ...
    
    
    int main()
    {
       Suit a = Suit::spades;
       ++a;                   // ok
       Moo b = Moo::moo;
       ++b;                   // compilation error, it's not my enum
    }
    
        2
  •  1
  •   Jans    7 年前

    您可以使用模板版本将其限制在所需的枚举上

    template <class E, std::enable_if_t<
        std::is_same_v<E, Suit> ||
        std::is_same_v<E, Rank>, bool> = true>
    E& operator++(E& r, int) {
        return r = (E)(static_cast<std::underlying_type_t<E>>(r) + 1);
    }