正如在别处所指出的那样,问题与命名空间无关,而是与使用|
创建一个 int 并试图将该值传递给期望一个enum
. 即使你“抛弃”了这个问题,你最终会在一个声称是 type 的变量中得到一个不协调的值Feeling::e
。
让enum
成员获得其自然有序的序列值通常更有帮助。这使得成员可以很容易地用作索引值,并且编译器通常能够更好地优化将它们用于计算 goto 的 switch 语句。但是,通常enum
需要像集合一样传递成员集合。
这是我用来将enum
's 转换为标志值的助手的简化版本。它对于已经定义了一个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
方法用于查看 anenum
是否是设置标志之一。
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
标志 or-d 一起转换为FlagsTmp
.
有几种方法可以扩展它以更好地满足您的需求,例如调整解决方案以使用bitset
,或添加额外的测试方法和运算符。