Как уже было отмечено, в другом месте, эта проблема не имеет ничего общего с пространствами имен, но с использованием |
для создания 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
или добавить дополнительные методы тестирования и операторы.
Это не имеет ничего общего с пространствами имен. – juanchopanza
Вы действительно думали о том, что значит быть счастливым и грустным в одно и то же время? Возможно, одно из перечислений должно быть «Psychotic» :-) – paxdiablo