Быстрый способ проверить диапазон значений enum - PullRequest
7 голосов
/ 09 декабря 2010

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

Пример:

enum fruit_and_vegetables
{
    apples,
    pears,
    tomatoes,
    cucumbers
}

int main()
{
    fruit_and_vegetables something = apples;
    if( something = {apples, pears} ) // <-- this here
        cout << "something is fruit." << endl;
    else
        cout "something is a vegetable." << endl;
    return 0;
}

Спасибо!

Ответы [ 7 ]

5 голосов
/ 09 декабря 2010

Не то, что я знаю, но вы можете назначить значения 2^i членам enum.Например:

enum fruit_and_vegetables
{
    apples    = (1<<0),
    pears     = (1<<1),
    tomatoes  = (1<<2),
    cucumbers = (1<<3)
    // ...
}

Затем вы можете проверить с помощью

if (something & (apples | pears | tomatoes))
  std::cout << "is tasty" << std::endl;

Конечно, это ограничено перечислениями с разумным размером (я думаю, вы можете иметь до 32 элементов).

РЕДАКТИРОВАТЬ

Если у вас есть более 32 (64) значений, вы должны быть более креативными, чем это.Выполнив несколько проверок, вы все равно можете быть достаточно быстрыми:

enum fruit_and_vegetables {
    apples    = 1, //!
    pears,
    tomatoes,
    cucumbers,
    // ...
    grapes
}
#define FRUIT_AND_VEGETABLES 120

if (   (1<<something)     & ((1<<apples) | (1<<pears) | (1<<tomatoes))
    || (1<<(something-32) & ((1<<(apples-32)) | (1<<(pears-32)) | (1<<(tomatoes-32))))
    || ...) {
  std::cout << "my keyboard is broken, but tastes good" << std::endl;
}

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

4 голосов
/ 10 декабря 2010

Ах, это можно сделать довольно легко ...

template <typename T>
pair<T, fruit_and_vegetables> operator||(T t, fruit_and_vegetables v) {
    return make_pair(t, v);
}

template <typename T>
bool operator==(fruit_and vegetables lhs, pair<T, fruit_and_vegetables> rhs) {
    return lhs == rhs.second || lhs == rhs.first;
}

Затем это можно использовать так:

if (something == (apple || pear || orange)) eat_the_yummy_fruit(something);
else feed_to_rabbit(something)

, но не будет работать, если вы сделаете (apple || (pear || orange)).Это можно легко исправить, но я хотел сохранить простой код.Я считаю, что это пока единственный ответ, который на самом деле масштабируется до больших перечислений ...

4 голосов
/ 09 декабря 2010

if (something < tomatoes)...

1 голос
/ 24 октября 2011

почему бы не использовать set< fruit_and_vegetables > для логического или нескольких fruit_and_vegetables?если вы поставите constexpr перед перегрузками оператора || и оператора ==, а также перед аргументами и типами результатов, то компилятор будет оценивать ваш код во время компиляции (без накладных расходов во время выполнения), если это возможно;) Хорошо масштабируетсяк большим a || b || c || c диапазонам перечислений, и вы можете указывать значения в скобках по своему усмотрению.

#include <set>
using std::set;

enum fruit_and_vegetables
{
    apples,
    pears,
    tomatoes,
    cucumbers
};

set< fruit_and_vegetables > operator||( fruit_and_vegetables left, fruit_and_vegetables right ) {
    set< fruit_and_vegetables > set;
    set.insert( left );
    set.insert( right );
    return set;
}

set< fruit_and_vegetables > operator||( set<fruit_and_vegetables> left, fruit_and_vegetables right ) {
    left.insert( right );
    return left;
}

set< fruit_and_vegetables > operator||( fruit_and_vegetables left, set<fruit_and_vegetables> right ) {
    right.insert( left );
    return right;
}

bool operator!=( fruit_and_vegetables lhs, set<fruit_and_vegetables> rhs ) {
    return ( rhs.find( lhs ) == rhs.end() );
}

bool operator==( fruit_and_vegetables lhs, set<fruit_and_vegetables> rhs ) {
    return !( lhs != rhs );
}

int main() {

fruit_and_vegetables fav = apples;
if ( fav == ( apples || (pears || tomatoes) ) ) cout << "match apples\n";
fav = cucumbers;
if ( fav == ( (apples || pears) || tomatoes ) ) cout << "Error! matched ghost cucumbers\n";
if ( fav != apples ) cout << "correct no match apples\n";
if ( fav == cucumbers ) cout << "default operator==(FaV, FaV) match\n";
if ( fav == ( pears || apples ) ) cout << "yummi\n";

return 0;
}
1 голос
/ 09 декабря 2010

Для обработки больших, несортированных наборов продуктов:

enum fruit_and_vegetables
{
    apples,
    pears,
    tomatoes,
    cucumbers,
    MAX_VALUE
};

vector<bool> arguablyVegetables(MAX_VALUE, false);
arguablyVegetables[tomatoes] = true;
arguablyVegetables[cucumbers] = true;

cout << arguablyVegetables[apples] << endl;
1 голос
/ 09 декабря 2010

Вы можете написать вспомогательный шаблон, который поможет вам достичь желаемого синтаксиса:

enum fruit_and_vegetables
{
    nothing,
    apples,
    pears,
    tomatoes,
    cucumbers
};

// helper template
typedef fruit_and_vegetables fav;
template<fav v1 = nothing, fav v2 = nothing, fav v3 = nothing, fav v4 = nothing,
  fav v5 = nothing, fav v6 = nothing, fav v7 = nothing, fav v8 = nothing>
bool check_equal( fruit_and_vegetables value )
{
    return ( value == v1 || value == v2 || value == v3 || value == v4 ||
             value == v5 || value == v6 || value == v7 || value == v8 );
}

// usage
int main()
{
    fruit_and_vegetables something = apples;
    if( check_equal<apples, pears>(something) )
        std::cout << "something is fruit." << std::endl;
    else
        std::cout << "something is a vegetable." << std::endl;

    return 0;
}
1 голос
/ 09 декабря 2010

Существует еще один способ, расширяющий ответ @bitmask:

Предположим, есть фиксированное количество критериев, которые вы можете проверить. Таким образом, вместо использования битовой маски для значений fruit_and_vegetables enum (что ограничит вас размером слова), вы можете использовать дополнительные LUT:

enum fruit_and_vegetables {
    apples  = 0,
    pears,
    tomatoes,
    cucumbers
}

enum qualifs {
   is_fruit = 1,
   is_sweet = 1<<1,
   is_round = 1<<2,
   is_tasty = 1<<3
}

const qualifs qualifs_LUT[] = { // can be generated
   is_fruit | is_sweet | is_round, // apple
    ...
};

так что проверка на определенный классификатор станет

if (qualifs_LUT[tomato] & is_tasty) 

РЕДАКТИРОВАТЬ : и еще один интересный метод. Рассмотрим (снова) метод @bitmask :. Это зависит от степени 2. Но как насчет простых чисел? Они растут намного медленнее, поэтому, присваивая простые числа перечислимым значениям, вы можете вычислить большее количество значений, предполагая, что продукт не переполнится:

enum fruit_and_vegetables {
    apples  = 2,
    pears = 3,
    tomatoes = 5,
    cucumbers = 7
}

if ((apples * pears * tomatoes) % tomatoes == 0)
     printf("it's tasty!");

этот ограничивает количество элементов в наборе управления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...