Как использовать перечисления в качестве флагов в C++?

В настоящий момент нет официального способа сделать это, но вы можете использовать небольшой трюк, чтобы достичь этого! Помните, что это экспериментально, и у него есть некоторые ограничения ... (проверьте эту ссылку , если вы беспокоитесь о совместимости с навигатором)

Что вы можете сделать, это использовать селектор CSS3: псевдо classe nth-child()

#list>* {
  display: inline-block;
  padding: 20px 28px;
  margin-right: 5px;
  border: 1px solid #bbb;
  background: #ddd;
  color: #444;
  margin: 0.4em 0;
}

#list :nth-child(-n+4) {
  color: #600b90;
  border: 1px dashed red;
  background: orange;
}

The oranges elements are the previous sibling li selected using li:nth-child(-n+4)

1

2

3

4
5

6

7

8

9

Ограничения

  • Вы не можете выбрать предыдущие элементы основанный на классах следующих элементов
  • Это то же самое для псевдо классов

171
задан Tony the Pony 19 September 2009 в 11:57
поделиться

7 ответов

"Правильный" способ - определить битовые операторы для перечисления, например:

enum AnimalFlags
{
    HasClaws   = 1,
    CanFly     = 2,
    EatsFish   = 4,
    Endangered = 8
};

inline AnimalFlags operator|(AnimalFlags a, AnimalFlags b)
{
    return static_cast<AnimalFlags>(static_cast<int>(a) | static_cast<int>(b));
}

И т. Д. остальные битовые операторы. При необходимости измените, если диапазон перечисления превышает диапазон int.

230
ответ дан 23 November 2019 в 20:41
поделиться

@Xaqq обеспечил действительно хороший безопасный с точки зрения типов способ использовать перечислимые флаги здесь flag_set класс.

я опубликовал код в GitHub, использование следующие:

#include "flag_set.hpp"

enum class AnimalFlags : uint8_t {
    HAS_CLAWS,
    CAN_FLY,
    EATS_FISH,
    ENDANGERED,
    ‿
};

int main()
{
    flag_set<AnimalFlags> seahawkFlags(AnimalFlags::HAS_CLAWS
                                       | AnimalFlags::EATS_FISH
                                       | AnimalFlags::ENDANGERED);

    if (seahawkFlags & AnimalFlags::ENDANGERED)
        cout << "Seahawk is endangered";
}
1
ответ дан 23 November 2019 в 20:41
поделиться

Я использую следующий макрос:

#define ENUM_FLAG_OPERATORS(T)                                                                                                                                            \
    inline T operator~ (T a) { return static_cast<T>( ~static_cast<std::underlying_type<T>::type>(a) ); }                                                                       \
    inline T operator| (T a, T b) { return static_cast<T>( static_cast<std::underlying_type<T>::type>(a) | static_cast<std::underlying_type<T>::type>(b) ); }                   \
    inline T operator& (T a, T b) { return static_cast<T>( static_cast<std::underlying_type<T>::type>(a) & static_cast<std::underlying_type<T>::type>(b) ); }                   \
    inline T operator^ (T a, T b) { return static_cast<T>( static_cast<std::underlying_type<T>::type>(a) ^ static_cast<std::underlying_type<T>::type>(b) ); }                   \
    inline T& operator|= (T& a, T b) { return reinterpret_cast<T&>( reinterpret_cast<std::underlying_type<T>::type&>(a) |= static_cast<std::underlying_type<T>::type>(b) ); }   \
    inline T& operator&= (T& a, T b) { return reinterpret_cast<T&>( reinterpret_cast<std::underlying_type<T>::type&>(a) &= static_cast<std::underlying_type<T>::type>(b) ); }   \
    inline T& operator^= (T& a, T b) { return reinterpret_cast<T&>( reinterpret_cast<std::underlying_type<T>::type&>(a) ^= static_cast<std::underlying_type<T>::type>(b) ); }

Это подобно тем упомянутым выше, но имеет несколько улучшений:

  • Это безопасно с точки зрения типов (это не предполагает, что базовый тип int)
  • , Это не требует для определения вручную базового типа (в противоположность ответу @LunarEclipse)

, Это действительно должно включать type_traits:

#include <type_traits>
1
ответ дан 23 November 2019 в 20:41
поделиться

Как указано выше (Кай) или сделайте следующее. На самом деле перечисления - это «Перечисления», вы хотите иметь набор, поэтому вам действительно следует использовать stl :: set

enum AnimalFlags
{
    HasClaws = 1,
    CanFly =2,
    EatsFish = 4,
    Endangered = 8
};

int main(void)
{
    AnimalFlags seahawk;
    //seahawk= CanFly | EatsFish | Endangered;
    seahawk= static_cast<AnimalFlags>(CanFly | EatsFish | Endangered);
}
2
ответ дан 23 November 2019 в 20:41
поделиться

Вкратце: вы действительно не знаете кодировку (набор символов), используемую в переменных, которые передаются в ваш PHP скрипт через GET или POST (особенно здесь проблема GET). По соглашению браузеры POST формируют серверный ресурс, указанный в атрибуте action , с использованием кодировки страницы, которая может быть указана с помощью http-Equiv -meta-tag ( charset -meta-tag в HTML5) или через HTTP-заголовок. В качестве альтернативы некоторые браузеры также учитывают атрибут accept-charset в форме при выборе правильной кодировки.

Кодирование параметров GET и самого URL-адреса зависит от настроек браузера и, следовательно, может контролироваться пользователь. Вы не должны полагаться на конкретную кодировку.

Как правило, вы обойдете большинство проблем, связанных с кодировкой, последовательно используя UTF-8 для всего и указав правильную кодировку в HTTP-заголовке ( Content-Type: text / html; charset = UTF-8 ) - это даст правильную кодировку (UTF-8) для всех переменных, которые передаются в вашу строку (мы не говорим о скриптах с румянцем, которые намеренно пытаются изменить кодировку, чтобы разрешить для некоторых векторов атаки в ваш скрипт). Вы также не должны полагаться на символы, отличные от ascii, в ваших параметрах GET или в URL-адресе (это также причина, по которой SEO-дружественные ссылки удаляют эти символы или заменяют их).

Если вы убедились, что UTF-8 является только разрешенный набор символов, вы можете использовать mb_strlen ($ string, 'UTF-8') , например, чтобы проверить длину переменной.

РЕДАКТИРОВАТЬ: (добавлено несколько ссылок)

Некоторые вещи для прочтения:

5
ответ дан 23 November 2019 в 20:41
поделиться

Самый простой способ сделать это, как показано здесь , с использованием стандартного библиотечного класса bitset .

Чтобы эмулировать функцию C # в типе: безопасным способом вам нужно будет написать оболочку шаблона вокруг битового набора, заменив аргументы int на перечисление, указанное в качестве параметра типа для шаблона. Примерно так:

    template <class T, int N>
class FlagSet
{

    bitset<N> bits;

    FlagSet(T enumVal)
    {
        bits.set(enumVal);
    }

    // etc.
};

enum MyFlags
{
    FLAG_ONE,
    FLAG_TWO
};

FlagSet<MyFlags, 2> myFlag;
18
ответ дан 23 November 2019 в 20:41
поделиться

К какому типу относится переменная seahawk.flags?

В стандартном C ++ перечисления не являются типобезопасными. По сути, это целые числа.

AnimalFlags НЕ должен быть типом вашей переменной, ваша переменная должна быть int, и ошибка исчезнет.

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

По умолчанию значения перечисления имеют тип int. Таким образом, вы можете поразрядно ИЛИ объединить их и соединить вместе и сохранить результат в int.

Тип enum - это ограниченное подмножество int, значение которого является одним из его перечислимых значений. Следовательно, когда вы создаете какое-либо новое значение за пределами этого диапазона, вы не можете присвоить его без преобразования в переменную вашего типа перечисления.

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

РЕДАКТИРОВАТЬ: Автор сообщения сказал, что они озабочены безопасностью типов и не хотят значения, которое не должно существовать внутри типа int.

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

Есть безопасный способ проверить значения вне диапазона, хотя внутри типа int ...

int iFlags = HasClaws | CanFly;
//InvalidAnimalFlagMaxValue-1 gives you a value of all the bits 
// smaller than itself set to 1
//This check makes sure that no other bits are set.
assert(iFlags & ~(InvalidAnimalFlagMaxValue-1) == 0);

enum AnimalFlags {
    HasClaws = 1,
    CanFly =2,
    EatsFish = 4,
    Endangered = 8,

    // put new enum values above here
    InvalidAnimalFlagMaxValue = 16
};

Вышесказанное не мешает вам поставить недопустимый флаг из другого перечисления, имеющего значение 1,2, 4 или 8.

Если вам нужна абсолютная безопасность типов, вы можете просто создать std :: set и хранить в нем каждый флаг. Это неэффективно по пространству, но является типобезопасным и дает те же возможности, что и битовый флаг int.

Примечание C ++ 0x: строго типизированные перечисления

В C ++ 0x вы, наконец, можете иметь безопасные для типов значения перечисления ....

enum class AnimalFlags {
    CanFly = 2,
    HasClaws = 4
};

if(CanFly == 2) { }//Compiling error
42
ответ дан 23 November 2019 в 20:41
поделиться