如何定义一个可扩展的C ++枚举系统(how to define an extensible C++

2019-09-21 16:20发布

我在我的枚举项目中遇到的问题。 在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 ++更好的编译时的解决方案作为模板,可以帮助这样的?

Answer 1:

扩展枚举的想法本身不是“糟糕的设计”。 在其他语言中有他们的历史,即使C ++不直接支持他们。 有不同种类的可扩展性。

的事情,可扩展的枚举将是有益的

  • 错误代码
  • 消息类型
  • 设备标识(OID是像系统的分层枚举)

枚举可扩展的例子

  • 目的MODULA两个具有可伸长与类如继承枚举。
  • 可扩展的枚举模式在Java中 ,可以在C ++中实现。
  • Java的枚举是可扩展的,额外的数据和方法可以是枚举的一部分。
  • 在C ++中,typeid操作符基本上与附接值的编译器生成的枚举。

你在你的代码示例展示了一种可扩展性并没有在独立的C ++优雅的实现。 事实上,正如你指出的那样,容易导致问题。

想想你是想如何使用一个可扩展的枚举。 也许是不可变单一对象的一组/图将满足您的需求。

以具有在C可扩展的枚举的另一种方式++是使用代码发生器。 想要添加到一个可扩展的枚举每个编译单元中,记录了自己的,独立的,.enum文件的ID。 在构建时,编译之前,一个脚本(即p​​erl的,bash中,...)查找所有.enum文件,读取它们,数值分配给每个ID,并写出一个头文件,它包含像任何其他。



Answer 2:

为什么你希望你的事件枚举被宣布这样呢? 你是什​​么让他们“链接”如果你愿意,他们的方式你描述获得什么?

我会让他们完全独立的枚举。 其次,我建议你不要使用旧风格枚举了。 C ++ 11是在这里,可以在海湾合作委员会。 您应该使用枚举类:

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重载函数您隔离所有enum类型。 让他们在不同的类别是利益不是问题。 它为您提供了灵活性,以应付每个事件枚举类型不同。

链接在一起你描述不必要的问题复杂化。

我希望帮助。



Answer 3:

我觉得复杂,功能和类型安全之间的以下有用的妥协。 它使用的是有一个默认的构造函数进行初始化方便的自定义类的全局变量。 下面的例子是一个可扩展的错误代码集。 你可能想也是一个命名空间中附上(但我通常不打扰)。

//
//  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&);
};


文章来源: how to define an extensible C++ enum system