将枚举类运算符模板化 [英] Templatize enum class operators
问题描述
我正在尝试使用C ++ 11枚举类创建标志位字段.我正在寻找一种模板化运算符的返回类型的方法,以便可以在下面的代码中使用它们:
I'm trying to create a flags bitfield using C++11 enum classes. I'm looking for a way to templatize the operators' return types so they can be used as in code below:
#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;
}
但是,有几个问题:
-
Flags flag = Flags::one | Flags::two | Flags::three;
无法推断类型为Flags
-
if (flag & Flags::four)
无法推断类型为bool
Flags flag = Flags::one | Flags::two | Flags::three;
can't deduce type to beFlags
if (flag & Flags::four)
can't deduce type to bebool
我是模板新手,在模板推导机制上有点迷失.另外,我尝试创建创建转换运算符
I'm new to templates and am kinda lost when it comes to template deduction mechanisms. Also, i tried to create create conversion operator
operator bool(const Flags& flag)
但没有结果.
推荐答案
首先创建一个帮助程序模板:
First create a helper template:
template<class E>
struct bool_or_enum{
E e;
explicit operator bool()const{return static_cast<bool>(e); }
operator E() const {return e;}
};
接下来,创建一个特征函数并输入:
Next, create a trait function and type:
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&>() ) );
}
现在magic_operators::use_algebra<E>
使用ADL搜索algebraic_enum
超载,并返回E
上的std::true_type
.这允许在任何地方启用魔术. MSVC 2015缺乏足够的C ++ 11支持来使用上述功能;替换为traits class.
Now magic_operators::use_algebra<E>
searches using ADL for algebraic_enum
overload returning std::true_type
on E
. This permits enabling the magic anywhere. MSVC 2015 lacks sufficient C++11 support to use the above; replace with traits class.
肉:我们的经营者.将它们放置在命名空间中,并使用using namespace
:
The meat: our operators. Stick them into a namespace and bring them in with 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) ) };
}
与|
类似.
对于~
和^
,您需要位掩码以保持定义的行为.有一个特征类enum_mask<E>
,该特征类默认为E::bit_mask
或类似的东西来获取它.
For ~
and ^
you need a bit mask to remain defined behaviour. Have a traits class enum_mask<E>
that defaults to E::bit_mask
or somesuch to get it.
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)) ) };
}
由于标准要求超出色域枚举,所以这很棘手.
This is tricky due to standards requirements on out of gamut enums.
|=
和&=
并不难,但是需要进行编码.同时支持赋值链接和隐式布尔的=
和|=
和&=
等需要更多的工作.我说不支持.
|=
and &=
isn't hard, but does need to be coded. =
and |=
and &=
etc that support both assignment chaining and implicit bool requires yet more work. I say do not support it.
哦,将所有内容标记为constexpr
,并将bool_or_enum<E>
重载添加到operator
中.
Oh and mark everything constexpr
and add bool_or_enum<E>
overloads to the operator
s.
以上代码未经测试或编译,但设计有效.
The above code is not tested or compiled, but the design works.
最终结果是:
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";
}
}
或类似的东西.
这篇关于将枚举类运算符模板化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!