我已经了解到,当两个枚举共享一个等同命名的项目时,将枚举放入命名空间可以避免编译错误。
namespace Feeling
{
enum e
{
Happy = 1,
Sad = 2,
Blue = 4,
Angry = 8,
Mad = 16
};
}
因此,您可以将其传递给声明为
的函数void HowDoYouFeel(Feeling::e feeling);
但是当尝试OR时,就像这样:
HowDoYouFeel(Feeling::Happy | Feeling::Blue);
我收到错误。处理这个问题的最佳方法是什么?
答案 0 :(得分: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
。
但是,注释掉第一个作业并使用第二个作业(使用其显式演员表)编译好了。
答案 1 :(得分:1)
这个问题要求“最好的方法”,这有点主观。我为这些案例写了e operator|(e left, e right) { return e(int(left)|int(right)); }
,以明确Feeling::e
有正交编码。
答案 2 :(得分:0)
枚举只不过是一个整数。您可以修改函数以使用整数(或无符号整数)作为输入,而不是枚举。
void HowDoYouFeel (int feelingMask);
然后像下面这样的调用就不会出错: -
HowDoYouFeel(Feeling::e::Happy | Feeling::e::Blue)
答案 3 :(得分:0)
正如其他地方所指出的那样,问题与命名空间无关,而是使用|
创建一个int,并尝试将该值传递给期望enum
的函数。即使你“抛弃”了这个问题,你也会在声称属于Feeling::e
类型的变量中得到一个不协调的值。
让enum
成员获得自然的有序顺序值通常会更有帮助。这允许成员容易地用作索引值,并且编译器通常更好地优化将它们用于计算的gotos的switch语句。但是,通常情况下,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
标记或-d一起变为FlagsTmp
。
有几种方法可以扩展它以更好地满足您的需求,例如调整解决方案以使用bitset
,或添加其他测试方法和运算符。
答案 4 :(得分:0)
您问题的简单答案: