类型为安全C ++ 11枚举类标志的模板 [英] Template for type safe c++11 enum class flags

查看:90
本文介绍了类型为安全C ++ 11枚举类标志的模板的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用模板创建类型安全的C ++标志。我还想区分 a 标志和flag s (为零,一个或多个标志)。

I am trying to create type safe C++ flags using templates. I also want to distinguish between a flag and flags (being zero, one or many flags).

除了 EnumFlag< T>之外,下面的解决方案效果很好。操作员| (T,T),这会导致对枚举的所有 | 操作返回类型 EnumFlag 。这会破坏很多代码。有什么技巧可以解决此问题?在我的代码中,我执行以下操作,但是 Option 的硬编码不是一个选项。

The solution below works good, except for EnumFlag<T> operator | (T, T) which causes all |-operations on enums to return type EnumFlag. This breaks lots of code. Any tricks to fix this? In my code I do the following, however hard coding Option here is not an option. How to make this generic?

EnumFlag<typename std::enable_if<std::is_same<T, Option>::value, T>::type> operator | (T l, T r)

将此更改为...

EnumFlag<T> operator | (T l, T r)

...原因会破坏一切。我想要这样的东西(不是compilabel代码)。或其他更好的主意!

...of cause breaks everything. I would like something like this (not compilabel code). Or any other better idea!

EnumFlag<typename std::enable_if<std::already_expanded<EnumFlag<T>>::value, T>::type> operator | (T l, T r)

完整的可编译代码:

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

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);
}

> 演示<

> DEMO <

实际代码将包含更多运算符,但这足以说明问题。

The actual code will contain a lot more operators, however this is enough to illustrate the problem.

一个较不侵入性的解决方案是(但仍然过于侵入性)

One less intrusive solution is this (but still too intrusive)

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));
}

不够神,然后 EnumFlag(const std: :underlying_type< T& flags)必须存在,并且我失去类型安全性。另外,我希望仅针对实际需要的类型创建全局运算符重载。宏也不是上帝,因为我想允许在类中声明 EnumFlag s。全局重载不可能存在,因此我需要在不同位置的两个宏调用在 EnumFlag 上创建。

Not god enough, then EnumFlag(const std::underlying_type<T> &flags) must exist and I lose type safty. Also, I would like for the global operator overloads to only be created for the types actually needed. Macros is also no god because I want ta allow declaration of EnumFlags inside classes. The global overloads can not be there, hence I need two macros calls at different locations to create on EnumFlag.

解决方案必须是纯C ++ 11 / stl。

The solution must be pure C++11/stl.

推荐答案

安东尼·威廉姆斯(Anthony Williams)有一个很好的Acticle,其中包含了现成的代码:将枚举类用作位域

Anthony Williams have a good acticle with ready code: "Using Enum Classes as Bitfields".

也许这正是您想要的。与我看到的其他解决方案不同,这里不使用宏-只是纯模板。

Maybe it's just what youre looked for. In difference from other solutions which I saw, macroes aren't used here - just pure templates.

一个简单的示例演示了他的解决方案:

Simple example demonstrating his solution:

#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;
}

bitmask_operators.hpp源代码

这篇关于类型为安全C ++ 11枚举类标志的模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆