模仿enum类操作符

tho*_*ter 3 c++ templates operator-overloading c++11

我正在尝试使用C++ 11枚举类创建标志位域.我正在寻找一种方法来模拟运算符的返回类型,以便它们可以在下面的代码中使用:

#include <iostream>

enum class Flags {
        one = 1,
        two = 1 << 1,
        three = 1 << 2,
        four = 1 << 3
};

#define _CONVERT(_operator) \
static_cast<T>(static_cast<int>(lhs) _operator static_cast<int>(rhs))

template <typename T>
T operator & (const Flags& lhs, const Flags& rhs) {
        return _CONVERT(&);
}

template <typename T>
T operator | (const Flags& lhs, const Flags& rhs) {
        return _CONVERT(|);
}

#undef _convert


int main()
{
        Flags flag = Flags::one | Flags::two | Flags::three;

        if (flag & Flags::two)
                std::cout << "Flag has two" << std::endl;

        if (flag & Flags::four)
                std::cout << "Flag has four" << std::endl;

        std::cout << static_cast<int>(flag) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

但是,有几个问题:

  • Flags flag = Flags::one | Flags::two | Flags::three; 不能推断出类型 Flags
  • if (flag & Flags::four) 不能推断出类型 bool

我是模板的新手,在模板演绎机制方面有点丢失.此外,我试图创建创建转换运算符

operator bool(const Flags& flag)
Run Code Online (Sandbox Code Playgroud)

但没有结果.

Yak*_*ont 8

首先创建一个帮助器模板:

template<class E>
struct bool_or_enum{
  E e;
  explicit operator bool()const{return static_cast<bool>(e); }
  operator E() const {return e;}
};
Run Code Online (Sandbox Code Playgroud)

接下来,创建一个特征函数并输入:

namespace magic_operators {
  template<class E>
  constexpr std::false_type algebraic_enum(E const volatile&) {return {};}

  template<class E>
  using use_algebra=decltype( algebraic_enum( std::declval<E const volatile&>() ) );
}
Run Code Online (Sandbox Code Playgroud)

现在magic_operators::use_algebra<E>搜索使用ADL的algebraic_enum过载恢复std::true_typeE.这允许在任何地方启用魔法.MSVC 2015缺乏足够的C++ 11支持来使用上述功能; 替换为traits类.

肉:我们的经营者.将它们粘贴到命名空间中并将它们带入using namespace:

template<class E, std::enable_if_t<magic_operators::use_algebra<E>{}, int> = 0>
bool_or_enum<E> operator&(E const& lhs, E const& rhs){
  using U = std::underlying_type_t<E>; 
  return { E( static_cast<U>(lhs) | static_cast<U>(rhs) ) };
}
Run Code Online (Sandbox Code Playgroud)

和类似的|.

对于~^你需要一个位掩码保持定义的行为.有一个特权类enum_mask<E>,默认为E::bit_mask或某些得到它.

template<class E, std::enable_if_t<magic_operators::use_algebra<E>{}, int> = 0>
bool_or_enum<E> operator^(E const& lhs, E const& rhs){
  using U = std::underlying_type_t<E>; 
  return { E( enum_mask<E>{} & (static_cast<U>(lhs) ^ static_cast<U>(rhs) ) ) };
}
template<class E, std::enable_if_t<magic_operators::use_algebra<E>{}, int> = 0>
bool_or_enum<E> operator~(E const& e){
  using U = std::underlying_type_t<E>; 
  return { E( enum_mask<E>{} & (~static_cast<U>(e)) ) };
}
Run Code Online (Sandbox Code Playgroud)

由于超出色域枚举的标准要求,这很棘手.

|=&=并不难,但是需要进行编码.=|=&=等同时支持分配链和隐式布尔还需要更多的工作.我说不支持它.

哦,标记一切,constexprbool_or_enum<E>operators 添加重载.

以上代码未经过测试或编译,但设计有效.


最终结果是:

enum class Bob { a=2, b=7, bit_mask = 0x00ff };
constexpr std::true_type algebraic_enum( Bob const& ){ return {}; }
using namespace algebraic_ops;

int main(){
  Bob x=Bob::a;
  x = x | Bob::b;
  if( x &~ Bob::b ){
    std::cout << "cast to bool bitmasking!\n";
  }
}
Run Code Online (Sandbox Code Playgroud)

或者某些人.