Использование флагов 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));