Реализация перечисления с использованием оператора |

Моя проблема заключается в том, что мне нужно реализовать возможность перечисления доступных для записи типов Severity, используемых в сообщениях. Это необходимо для того, чтобы иметь возможность фильтровать сообщения по степени серьезности в классе Logger. Severity является enum классом:

enum class Severity: uint8_t
{
    EMERGENCY   = 0, // System is unusable
    ALERT       = 1, // Action must be taken immediately
    CRITICAL    = 2, // Critical conditions
    ERROR       = 3, // Error conditions
    WARNING     = 4, // Warning conditions
    NOTICE      = 5, // Normal but significant condition
    INFO        = 6, // Informational
    DEBUG       = 7, // Debug level messages
};

На данный момент я вижу только одно действующие решения этой проблемы. А решение состоит в том, чтобы иметь два открытых метода в классе Logger:

void addSeverity(Severity severity);
void rmvSeverity(Severity severity);

которые будут отвечать за добавление и удаление типов серьезности. Например, если определенное Severity добавлено, игнорирование сообщений с таким типом производится не будет.

Но мне бы хотелось, иметь такую возможность, указанную в коде ниже (в данном случае, мы будем иметь возможность записывать лишь 3 типа Severity):

void setSeveritySupports(Severity);

// ... 

setSeveritySupports(Severity::INFO | Severity::WARNING | Severity::ERROR);

Я могу перегрузить оператор | таким способом :

Severity operator|(Severity l, Severity r)
{
    return Severity(static_cast<int>(l) | static_cast<int>(r));
}

но в таком случае, я максимум что могу, это установть максимальное значение Severity.


Ответы (1 шт):

Автор решения: Павел Ериков

Что-то типа такого?

enum Severity : uint8_t
{
    EMERGENCY = 0x01, // System is unusable
    ALERT     = 0x02, // Action must be taken immediately
    CRITICAL  = 0x04, // Critical conditions
    ERROR     = 0x08, // Error conditions
    WARNING   = 0x10, // Warning conditions
    NOTICE    = 0x20, // Normal but significant condition
    INFO      = 0x40, // Informational
    DEBUG     = 0x80, // Debug level messages
};

inline const char* severityToString(uint8_t sev) {
    switch (sev) {
    case EMERGENCY: return "Emergency";
    case ALERT:     return "Alert";
    case CRITICAL:  return "Critical";
    case ERROR:     return "Error";
    case WARNING:   return "Warning";
    case NOTICE:    return "Notice";
    case INFO:      return "Info";
    case DEBUG:     return "Debug";
    default:        return "";
    }
}

void setSeveritySupports(uint8_t flag) {
    uint8_t tmp = flag;
    uint8_t mask = 0x1;
    while (tmp > 0) {
        if(tmp & 1)
            cout << "Установлен флаг: " << severityToString(flag & mask) << endl;
        mask <<= 1;
        tmp >>= 1;
    }
} 

int main()
{
    setlocale(LC_ALL, "Russian");
    setSeveritySupports(Severity::ALERT | Severity::INFO | Severity::ERROR | Severity::DEBUG);

    return 0;
}

Результат программы:

Результат

Используем в качестве значений степени двойки, т.к. возьмем 2 числа являющиеся степенями двойки, например 64 и 8, в двоичной системе счисления они будут выглядеть так:

64 = ...0010000
8  = ...0000100

Воспользовавшись оператором | (побитовое ИЛИ), мы сможем упаковать эти два числа в одно.

64 = ...0010000 |
8  = ...0000100 =
20 = ...0010100

И теперь по этому числу мы сможем получить обратно число 64 и 8.

По ссылке которую предложил wololo вы можете почитать об этой теме.

P.s. Так как у вас 8 значений в enum, то максимальное значение будет `2^

→ Ссылка