我的枚举项目中遇到了问题。 在EventDef.h中,
enum EventDef {
EVT1 = 0,
EVT2,
EVT3,
EVT_NUM,
}
通过这种方式,我可以通过
扩展另一个头文件UIEventDef.h中的EventDef系统#include "EventDef.h"
enum UIEventDef {
UIEVT1 = EVT_NUM,
UIEVT2,
UIEVT3,
}
但是,我无法以同样的方式在NetEvent.h中执行此操作。
#include "EventDef.h"
enum NetEventDef {
NETEVT1 = EVT_NUM,
NETEVT2, //wrong: this will have the same value as UIEVT2
NETEVT3,
}
在C ++中是否有更好的编译时解决方案,例如可以提供帮助的模板?
答案 0 :(得分:6)
可扩展枚举的概念本身并不是“糟糕的设计”。在其他语言中有它们的历史,即使c ++不直接支持它们。有不同类型的可扩展性。
可扩展枚举的内容对
有用枚举可扩展性的示例
您在示例代码中显示的可扩展性在单独的c ++中没有优雅的实现。事实上,正如你所指出的,它很容易导致问题。
考虑一下您希望如何使用可扩展的枚举。也许不可变单例对象的集合/映射将满足您的需求。
在c ++中使用可扩展枚举的另一种方法是使用代码生成器。每个想要添加到可扩展枚举的编译单元都将id记录在它自己的单独的.enum文件中。在构建时,在编译之前,脚本(即perl,bash,...)查找所有.enum文件,读取它们,为每个id分配数值,并写出一个与任何其他文件一样包含的头文件。
答案 1 :(得分:2)
为什么要将您的事件枚举声明为这样?如果你愿意的话,你可以通过他们的方式将他们“联系起来”获得什么?,
我会让它们完全独立的枚举。其次,我建议你不要再使用旧式的枚举了。 c ++ 11在这里,在gcc中可用。你应该使用枚举类:
enum class EventDef : unsigned { Evt1 = 0, Evt2, Evt3, ... LastEvt }
enum class NetEvtDef : unsigned { NetEvt1 = 0, NetEvt2, NetEvt3, ... NetLastEvt }
如果你要转换,你可以这样做:
void doSwitch(EventDef evt_def)
{
switch(evt_def)
{
case EventDef::Evt1
{
// Do something;
break;
}
default:
// Do something;
};
}
void doSwitch(NetEvtDef net_def)
{
switch(net_def)
{
case NetEvtDef::NetEvt1
{
// Do something;
break;
}
default:
// Do something;
};
}
通过为doSwitch创建重载函数,您可以隔离所有枚举类型。将它们分成不同的类别是一个好处而不是问题。它为您提供了以不同方式处理每个事件枚举类型的灵活性。
在描述时将它们链接在一起不必要地使问题复杂化。
我希望有所帮助。
答案 2 :(得分:0)
我发现以下是复杂性,功能和类型安全性之间的有用折衷。它使用具有默认构造函数的自定义类的全局变量来简化初始化。以下示例是一组可扩展的错误代码。您可能也想要在名称空间中包含(但我通常不会打扰)。
//
// ErrorCodes.h
// ExtendableEnum
//
// Created by Howard Lovatt on 10/01/2014.
//
#ifndef ErrorCodes_h
#define ErrorCodes_h
#include <string>
class ErrorCodes {
public:
static int nextValue_;
explicit ErrorCodes(std::string const name) : value_{nextValue_++}, name_{name} {}
ErrorCodes() : ErrorCodes(std::to_string(nextValue_)) {}
int value() const { return value_; }
std::string name() const { return name_; }
private:
int const value_;
std::string const name_;
ErrorCodes(const ErrorCodes &);
void operator=(const ErrorCodes &);
};
int ErrorCodes::nextValue_ = 0; // Weird syntax, does not declare a variable but rather initialises an existing one!
ErrorCodes first;
ErrorCodes second;
// ...
#endif
//
// ExtraErrorCodes.h
// ExtendableEnum
//
// Created by Howard Lovatt on 10/01/2014.
//
#ifndef ExtraErrorCodes_h
#define ExtraErrorCodes_h
#include "ErrorCodes.h"
ErrorCodes extra{"Extra"};
#endif
//
// ExtraExtraExtraCodes.h
// ExtendableEnum
//
// Created by Howard Lovatt on 10/01/2014.
//
#ifndef ExtendableEnum_ExtraExtraCodes_h
#define ExtendableEnum_ExtraExtraCodes_h
#include "ErrorCodes.h"
ErrorCodes extraExtra{"ExtraExtra"};
#endif
//
// main.cpp
// ExtendableEnum
//
// Created by Howard Lovatt on 10/01/2014.
//
#include <iostream>
#include "ErrorCodes.h"
#include "ExtraErrorCodes.h"
#include "ExtraExtraErrorCodes.h"
// Need even more error codes
ErrorCodes const localExtra;
int main(int const notUsed, const char *const notUsed2[]) {
std::cout << first.name() << " = " << first.value() << std::endl;
std::cout << second.name() << " = " << second.value() << std::endl;
std::cout << extra.name() << " = " << extra.value() << std::endl;
std::cout << extraExtra.name() << " = " << extraExtra.value() << std::endl;
std::cout << localExtra.name() << " = " << localExtra.value() << std::endl;
return 0;
}
输出结果为:
0 = 0
1 = 1
Extra = 2
ExtraExtra = 3
4 = 4
如果您有多个编译单元,则需要在单例模式上使用变体:
class ECs {
public:
static ErrorCode & first() {
static ErrorCode instance;
return instance;
}
static ErrorCode & second() {
static ErrorCode instance;
return instance;
}
private:
ECs(ECs const&);
void operator=(ECs const&);
};
答案 3 :(得分:0)
我们可以在C ++中构造一个可扩展的“枚举”,如下所示:
struct Last {};
struct D
{
using Next = Last;
static const char* name = “D”;
};
struct C
{
using Next = D;
static const char* name = “C”;
};
struct B
{
using Next = C;
static const char* name = “B”;
};
using First = B;
我们可以使用以下结构遍历以上内容:
void Process(const B&)
{
// do something specific for B
cout << “Call me Ishmael” << endl;
}
template <class T>
void Process(const T&)
{
// do something generic
cout << “Call me “ << T::name << endl;
}
template <class T>
struct IterateThru
{
static void iterate()
{
Process(T());
IterateThru<T::Next>::iterate();
}
};
template <>
struct IterateThru<Last>
{
static void iterate()
{
// end iteration
}
};
要遍历“枚举”:
IterateThru<First>::iterate();
要扩展“枚举”:
struct A
{
using Next = B;
static const char* name = “A”;
}:
using First = A: