Mat*_*ias 5 c++ enums templates type-safety c++11
我试图使用模板创建类型安全的C++标志.我也想区分一个标志和标志小号(是零,一个或多个标志).
下面的解决方案运行良好,除非EnumFlag<T> operator | (T, T)导致|枚举上的所有操作返回类型EnumFlag.这打破了很多代码.有什么技巧可以解决这个问题?在我的代码中,我执行以下操作,但是Option这里的硬编码不是一个选项.如何使这个通用?
EnumFlag<typename std::enable_if<std::is_same<T, Option>::value, T>::type> operator | (T l, T r)
Run Code Online (Sandbox Code Playgroud)
将此更改为......
EnumFlag<T> operator | (T l, T r)
Run Code Online (Sandbox Code Playgroud)
...的原因打破了一切.我想要这样的东西(不是compilabel代码).或者任何其他更好的主意!
EnumFlag<typename std::enable_if<std::already_expanded<EnumFlag<T>>::value, T>::type> operator | (T l, T r)
Run Code Online (Sandbox Code Playgroud)
完整的可编辑代码:
EnumFlag.h
#ifndef __classwith_flags_h_
#define __classwith_flags_h_
#include <type_traits>
enum class Option
{
PrintHi = 1 << 0,
PrintYo = 1 << 1,
PrintAlot = 1 << 2
};
template <typename T>
class EnumFlag
{
public:
using UnderlayingType = typename std::underlying_type<T>::type;
EnumFlag(const T& flags)
: m_flags(static_cast<UnderlayingType>(flags))
{}
bool operator & (T r) const
{
return 0 != (m_flags & static_cast<UnderlayingType>(r));
}
static const T NoFlag = static_cast<T>(0);
private:
UnderlayingType m_flags;
};
template<typename T>
EnumFlag<typename std::enable_if<std::is_same<T, Option>::value, T>::type> operator | (T l, T r)
{
return static_cast<T>(static_cast<typename EnumFlag<T>::UnderlayingType>(l) | static_cast<typename EnumFlag<T>::UnderlayingType>(r));
}
class ClassWithFlags
{
public:
using Options = EnumFlag < Option >;
void doIt(const Options &options);
};
#endif
Run Code Online (Sandbox Code Playgroud)
EnumFlag.cpp
#include "EnumFlag.h"
#include <iostream>
void ClassWithFlags::doIt(const Options &options)
{
if (options & Option::PrintHi)
{
std::cout << "Hi" << std::endl;
}
if (options & Option::PrintYo)
{
std::cout << "Yo!" << std::endl;
}
}
int main()
{
ClassWithFlags classWithFlags;
classWithFlags.doIt(Option::PrintHi | Option::PrintAlot);
}
Run Code Online (Sandbox Code Playgroud)
> 演示 <
实际代码将包含更多运算符,但这足以说明问题.
一个较少侵入性的解决方案就是这个(但仍然过于干扰)
template<typename T>
typename std::underlying_type<T>::type operator | (T l, T r)
{
return (static_cast<typename std::underlying_type<T>::type>(l) | static_cast<typename std::underlying_type<T>::type>(r));
}
Run Code Online (Sandbox Code Playgroud)
不够神,那么EnumFlag(const std::underlying_type<T> &flags)必须存在,我失去了类型安全.另外,我希望全局运算符重载只能为实际需要的类型创建.宏也不是神,因为我想要允许EnumFlag在类内部声明s.全局重载不可能存在,因此我需要在不同位置进行两次宏调用来创建EnumFlag.
解决方案必须是纯C++ 11/stl.
安东尼威廉姆斯有一个很好的代码与准备代码:"使用枚举类作为位域".
也许这就是你所寻求的.与我看到的其他解决方案不同,这里不使用宏 - 只是纯模板.
举例说明他的解决方案:
#include "bitmask_operators.hpp"
enum class A{
x=1,y=2
};
enum class B:unsigned long {
x=0x80000000,y=0x40000000
};
template<>
struct enable_bitmask_operators<A>{
static const bool enable=true;
};
template<>
struct enable_bitmask_operators<B>{
static const bool enable=true;
};
enum class C{x,y};
int main(){
A a1=A::x | A::y;
A a2=a1&A::y;
a2^=A::x;
A a3=~a1;
B b1=B::x | B::y;
B b2=b1&B::y;
b2^=B::x;
B b3=~b1;
// C c1=C::x | C::y;
// C c2=c1&C::y;
// c2^=C::x;
// C c3=~c1;
}
Run Code Online (Sandbox Code Playgroud)
以下是我的做法,希望您会发现它有用。
主要问题是如何区分枚举标志和所有其他类型。我会使用额外的模板类型,例如flag_type,它只有一个成员用于value我们的枚举标志:
template<typename T>
typename flag_type<T>::value operator | (T, T)
{
/* implementation */
}
Run Code Online (Sandbox Code Playgroud)
默认flag_type为空
template<typename T>
struct flag_type {};
Run Code Online (Sandbox Code Playgroud)
而对于枚举标志,它将包含EnumFlag从 . 返回的类型operator|。这是一个执行此操作的宏:
#define DECLARE_FLAG_TYPE(__type) \
template<> \
struct flag_type<__type> { using value = EnumFlag<__type>; }
Run Code Online (Sandbox Code Playgroud)
然后,我们可以使用它在外部作用域和类中定义枚举标志:
enum class Option
{
One = 1 << 0,
Two = 1 << 1,
Three = 1 << 2
};
DECLARE_FLAG_TYPE(Option);
class Class
{
public:
enum class Option
{
Four = 1 << 0,
Five = 1 << 1
};
};
DECLARE_FLAG_TYPE(Class::Option);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5914 次 |
| 最近记录: |