简体   繁体   English

在编译时将整数转换为位掩码而不使用宏

[英]Converting an integer to a bitmask in compile time not using macro

TLDR: Provide a "bitmask" class with a constexpr constructor that creates the bitmask based on the input parameter (applying a bitshift) in the compile-time, which could be used instead of a function-like MACRO. TLDR:提供一个带有 constexpr 构造函数的“位掩码”类,该构造函数在编译时根据输入参数(应用位移位)创建位掩码,可以用来代替类似函数的 MACRO。

I'm trying to implement an event manager that stores events as bit flags.我正在尝试实现一个将事件存储为位标志的事件管理器。 This would be a wrapper for an RTOS feature such as event flag group这将是 RTOS 功能(例如事件标志组)的包装器

I would like to have the events specified this way我想以这种方式指定事件

enum Event
{
    FOO,
    BAR,
    BAZ,
};

Not this way:不是这样:

// This construct is harder to maintain and easier to make a mistake
enum Event
{
    FOO = 0b0001,
    BAR = 0b0010,
    BAZ = 0b0100,
};

The events would be then used in this way:然后将以这种方式使用这些事件:

class EventService
{
    uint32_t current_events;

public:
    void set_event(const EventMask ev)
    {
        current_events |= ev.mask;
    }

    bool check_event(const EventMask ev)
    {
        const bool was_set = current_events & ev.mask != 0;
        current_events &= ~(ev.mask);
        return was_set;
    }

};

EventService s;

void event_producer()
{
    s.set_event(Event::FOO); 
}

void event_handler()
{
    if(s.check_event(Event::FOO))
    {
        // do something;
    }

    if(s.check_event(Event::BAR))
    {
        // do something else;
    }

    if(s.check_event(Event::BAZ))
    {
        // do something else;
    }
}

Therefore I've implemented a helper class EventMask with constexpr constructor that just makes a bit shift and stores it as a const member.因此,我使用 constexpr 构造函数实现了一个辅助类EventMask ,它只是进行位移并将其存储为 const 成员。

struct EventMask
{    
    const uint32_t mask;

    template<typename Enum>
    constexpr EventMask(Enum event_id) : mask(1u << event_id)
    {
        static_assert(std::is_enum<Enum>::value, "Enum required.");
        constexpr_assert(event_id <= MAX_ID);
    }
};

But unfortunately, these bitmask objects are not created in the build-time while using check_event and set_event .但不幸的是,这些位掩码对象不是在使用check_eventset_event时在构建时创建的。 Here is the whole example put together.是放在一起的整个示例。

set_event(Event::FOO);
check_event(Event::BAZ); //this should fail in the conpile time because I set BAZ to be higher then MAX_ID

I know I could have a MACRO wrapper around set_event and check_event but I believe there is a more modern way (probably I just don't understand the constexpr in the first place.) On the other hand, I could have a template with a template argument N and body 1u << N but this would make the code bloat, wouldn't it?我知道我可以在set_eventcheck_event周围有一个 MACRO 包装器,但我相信有一种更现代的方式(可能我一开始就不理解 constexpr。)另一方面,我可以有一个带有模板的模板参数N和 body 1u << N但这会使代码膨胀,不是吗?

I've been thinking about consteval but this will not allow to send a runtime event (like stored somewhere as a configuration) which appears as a valid usecase我一直在考虑consteval但这将不允许发送显示为有效用例的运行时事件(例如作为配置存储在某处)

Not really an answer why your assertion doesn't work but I avoid the problem with:不是一个真正的答案,为什么你的断言不起作用,但我避免了这个问题:

enum class Bits
{
    FOO,
    BAR,
    BAZ,
};

enum class Event
{
    FOO = 1llu << int(Bits::FOO),
    BAR = 1llu << int(Bits::BAR),
    BAZ = 1llu << int(Bits::BAZ),
};

Event operator |(const Event &lhs, const Event &rhs) {
    return Event(int(lhs) | int(rhs));
}

Event x = Event::FOO | Event::BAR;

Lots of boilerplate but it works.很多样板,但它的工作原理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM