Использование флагов C в С++

У меня есть API-интерфейс C, который определяет перечисление следующим образом:

typedef enum
{
  C_ENUM_VALUE_NONE    = 0,
  C_ENUM_VALUE_APPLE   = (1 << 0),
  C_ENUM_VALUE_BANANA  = (1 << 1),
  C_ENUM_VALUE_COCONUT = (1 << 2),
  // etc.
  C_ENUM_VALUE_ANY     = ~0
} CEnumType;

Существует метод, который использует перечисление, определяемое как:

void do_something(CEnumType types);

В C вы можете вызвать что-то вроде:

do_something(C_ENUM_VALUE_APPLE | C_ENUM_VALUE_BANANA);

Однако, если вы попытаетесь называть его таким образом в С++ (Linux, g++ компилятор), вы получите ошибку, неверное преобразование из 'int в' CEnumType.

Каков правильный способ использования этого C API из моего приложения на С++?

Ответ 1

Вам нужно указать int на перечисления в С++, но вы можете скрыть приведение в пользовательском OR:

CEnumType operator|(CEnumType lhs, CEnumType rhs) {
    return (CEnumType) ((int)lhs| (int)rhs);
}

С помощью этого оператора вы можете записать оригинал

do_something(C_ENUM_VALUE_APPLE | C_ENUM_VALUE_BANANA);

и он будет скомпилирован и запущен без проблем.

Ответ 2

С++ имеет более строгие правила, чем C в отношении перечислений. Вам нужно указать значение для типа перечисления при вызове:

do_something((CEnumType)(C_ENUM_VALUE_APPLE | C_ENUM_VALUE_BANANA));

В качестве альтернативы вы можете записать функцию-обертку, которая принимает int, чтобы сделать бросок для вас, если вы хотите избежать написания приведения каждый раз, когда вы его вызываете:

void do_something_wrapper(int types)
{
    do_something((CEnumType)types);
}
...
do_something_wrapper(C_ENUM_VALUE_APPLE | C_ENUM_VALUE_BANANA);

Хотя я не знаю, хочу ли я видеть, что вы получаете, когда вы пересекаете яблоко с бананом...

Ответ 3

В случае побитовых операций выражение оценивается как примитивный тип, т.е. int, long и т.д. Однако ваша функция принимает не примитивный тип (CEnumType). Единственный способ, которым я знаю обходить это, - это выразить выражение. Например:

do_something((CEnumType) (C_ENUM_VALUE_APPLE | C_ENUM_VALUE_BANANA));

Ответ 4

CEnumType A;

A = (CEnumType) (A | C_ENUM_VALUE_APPLE);

Вы также можете использовать его так.

Ответ 5

Посредством двух значений enum вы создаете недопустимое значение (0x3 не указано в enum CEnumType). Перечисления не являются битовыми полями. Если вы хотите бит-поле, определите его.

Вы можете указать значение, если хотите его пропустить, но это может удивить некоторый код, который рассчитывает только на возможность получить перечисленные значения.

do_something((CEnumType)(C_ENUM_VALUE_APPLE | C_ENUM_VALUE_BANANA));