2012-06-05 3 views
0

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

namespace Feeling 
{ 
    enum e 
    { 
     Happy = 1, 
     Sad = 2, 
     Blue = 4, 
     Angry = 8, 
     Mad = 16 
    }; 
} 

Таким образом, вы можете передать его функции, которые объявлены как

void HowDoYouFeel(Feeling::e feeling); 

Но при попытке или это так:

HowDoYouFeel(Feeling::Happy | Feeling::Blue); 

Я получаю сообщение об ошибке. Каков наилучший способ справиться с этим?

+0

Это не имеет ничего общего с пространствами имен. – juanchopanza

+0

Вы действительно думали о том, что значит быть счастливым и грустным в одно и то же время? Возможно, одно из перечислений должно быть «Psychotic» :-) – paxdiablo

ответ

1

Вопрос задает вопрос «лучший метод», который немного субъективен. Я пишу e operator|(e left, e right) { return e(int(left)|int(right)); } для этих случаев, чтобы было ясно, что Feeling::e имеет ортогональное кодирование.

5

Когда подробно проблему, следует указать:

  • минимальный пример кода, который демонстрирует проблему;
  • ожидаемое поведение; и
  • фактическое поведение.

В этом случае у вас отсутствует ошибка, которую вы получаете. Например, следующий код:

namespace Feeling { 
    enum e { Happy = 1, Sad = 2, Blue = 4, Angry = 8, Mad = 16 }; 
} 

int main() { 
    Feeling::e ff1; 
    ff1 = Feeling::Happy | Feeling::Sad; 
    // ff1 = (Feeling::e)(Feeling::Happy | Feeling::Sad); 
    return 0; 
} 

выдает ошибку:

error: invalid conversion from ‘int’ to ‘Feeling::e’ 

, так как результат оператора | является int.

Однако комментирование первого задания и использование второго (с его явным приложением) компилируются в порядке.

0

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

void HowDoYouFeel (int feelingMask); 

Тогда вызов, как следующий не даст без ошибки: -

HowDoYouFeel(Feeling::e::Happy | Feeling::e::Blue) 
+0

Это один из способов сделать это, но я не настолько большой поклонник удаления безопасности типа. – paxdiablo

+0

Это может быть не самый лучший способ, но вы можете добавить больше записей в список перечислений, чтобы указать, что вам нужно, например: - enum {Happy = 1, Sad = 2, Blue = 4, HappyBlue = 5} Если все такие «или» результаты являются частью перечисления, не было бы ошибки, так как «int» также был бы перечислением «Feeling». Но это определенно не масштабируемое решение. Но это также гарантирует, что «oring» действителен только в тех случаях, которые вы разрешаете. Например, Happy | Грустный недействителен, если «3» не указан в перечислении. – rajatkhanduja

+0

@paxdiablo, но предложение, которое вы предлагаете, также небезопасно, поскольку оно может давать значения, которые не входят в перечисление ... – juanchopanza

0

Как уже было отмечено, в другом месте, эта проблема не имеет ничего общего с пространствами имен, но с использованием | для создания Int, и пытается передать это значение в функцию, ожидающую enum. Даже если вы «отбросили» проблему, вы получите несоответствующее значение в переменной, которая утверждает, что она является типом Feeling::e.

Часто бывает полезно, чтобы члены enum получали свои естественные последовательные значения в порядке. Это позволяет членам легко использоваться в качестве значений индекса, а компилятор часто лучше оснащен оптимизацией операторов switch, которые используют их в вычисленных gotos. Однако часто бывает, что набор членов enum должен проходить как набор.

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

namespace Feeling { 
    enum e { Happy, Sad, Blue, Angry, Mad, MAX_e }; 
    std::string estr[] = { "Happy", "Sad", "Blue", "Angry", "Mad" }; 
} 

void HowDoYouFeel (const Flags<Feeling::e> &feelings) 
{ 
    for (int i = 0; i < Feeling::Max_e; ++i) { 
     if (feelings.has(i)) std::cout << Feeling::estr[i] << std::endl; 
    } 
    if (feelings.has(Feeling::Angry)) { 
     std::cout << "The Hulk is in the house." << std::endl; 
    } 
} 

HowDoYouFeel(Feeling::Happy | Feeling::Blue | Feeling::Mad); 

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

template <typename E> 
class Flags 
{ 
    unsigned long long m_opts; 
public: 
    Flags() : m_opts(0) {} 
    Flags (E e) : m_opts(1ULL << e) {} 
    Flags (const FlagsTmp<E> &ot) : m_opts(ot.m_opts) {} 

    bool has (unsigned i) const { return m_opts & (1ULL << i); } 
    bool has (E e) const { return m_opts & (1ULL << e); } 
}; 

Flags шаблона принимает enum типа в качестве параметра шаблона, а также обеспечивает некоторые простые способы инициализации. Метод has используется для определения того, является ли enum одним из установленных флагов.

template <typename E> 
class FlagsTmp 
{ 
    friend class Flags<E>; 
    mutable unsigned long long m_opts; 
public: 
    FlagsTmp (E e) : m_opts(1ULL << e) {} 
    const FlagsTmp & operator | (E e) const { 
     m_opts |= (1ULL << e); 
     return *this; 
    } 
}; 

FlagsTmp используется в качестве посредника, чтобы собрать все флаги. Он позволяет связать флаги вместе с операциями | в одном экземпляре FlagsTmp.

template <typename E> 
FlagsTmp<E> operator | (E e, E f) { return FlagsTmp<E>(e) | f; } 

Этот оператор перегружает оператор |, чтобы включить два или enum флаги-й вместе в FlagsTmp.

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

0

Простой ответ на вопросы:

  1. Ничего общего с пространством имен.
  2. Имеются скрытые конверсии в вашем телефоне: Чувство :: Счастливое | Feeling :: Blue вызовет преобразование из enum в интеграл. HowDoYouFeel (Feeling :: Happy | Feeling: Blue) вызовет преобразование из интеграла в перечисление, которое не разрешено компилятором, следовательно, ошибка.
Смежные вопросы