3

假设您正在编写一个库,为一个类提供某种“类型”参数。为此,可能会使用枚举:

namespace MyLib {
  class Event {
  public:
    enum EventType { TYPE1, TYPE2, ... };
    Event(EventType _type) : type(_type) { }
  private:
    EventType type;
  }
}

然后实例化:

new MyLib::Event(Event::TYPE1);

到目前为止还好。但是,如果您希望用户能够扩展事件类型列表怎么办?如果 type 属性是枚举,这是不可能的。

低质量的可能性包括要求他们#define自定义事件名称,或者简单地使用字符串,尽管这些似乎都不是最理想的。

有一个通用的解决方案吗?

一个建议是使用 astruct EventType返回枚举中指定范围内的值。然而,虽然这解决了编译器安全问题,但它并没有解决添加命名类型的问题——它需要用户将这些添加到全局范围。

解决后一个问题但不是前一个问题的一种可能性是将 EventType 类型定义为一个整体类型,并将其留给用户将自定义类型添加到库的名称空间或他们自己的名称空间。提供唯一值的工厂方法可以作为 Event 的一部分提供:

#include <iostream>
#include <vector>

namespace MyLib {

  namespace EventType {
    typedef int T;
    enum { TYPE1, TYPE2, Count};
  }

  class Event {
  public:
    Event(EventType::T _type) : type(_type) { }
    EventType::T type;
    static EventType::T registerType() { return _typeid++; }
  private:
    static int _typeid;
  };

}

MyLib::EventType::T MyLib::Event::_typeid = EventType::Count;

// The user can then add types, including to the library's namespace
// (which may or may not be a good idea)
namespace MyLib { namespace EventType {
  MyLib::EventType::T MYTYPE = MyLib::Event::registerType();
} }

int main() {
  MyLib::Event ev1(MyLib::EventType::TYPE2);
  MyLib::Event ev2(MyLib::EventType::MYTYPE);
  std::cout << ev1.type << std::endl;
  std::cout << ev2.type << std::endl;
  return 0;
}

输出:

1
2

虽然这在技术上并未将参数限制为一组已注册的类型,但 typedef 和命名空间在 IDE 中的构造函数定义和自动建议中提供了有用的语法提示,并且它可以防止用户类型不得不污染全局范围,从而也许是更大的担忧。

有没有更好的方法来指定有限的、经过编译器检查但用户可扩展的值集作为类的类型参数,或者通常是函数/方法?

4

3 回答 3

2

我认为你最好的选择是简单地将事件类型作为一个普通的整数类型,使用枚举来定义内置类型,并提供用户定义的最小值和最大值,用户在它们之间创建自己的整数值枚举器。然后,您只需使用断言来确保基本事件不会尝试处理未知事件类型。

编辑:请注意,具有某些类型的基事件类可以理解,而某些类型可能不脆弱,除非它只是为子类保存数据以供以后再次选择。即使在这种情况下,考虑替代设计可能会更好。您能否详细说明事件类型在设置后如何使用

EDIT2:我想我现在理解得更好了,事件存储事件类型,事件使用者可以从事件中检索它。如果消费者理解扩展事件类型,它可以进行适当的处​​理,否则委托、断言或简单地无操作。鉴于此,我认为使用整数事件类型似乎很好。

于 2012-08-10T16:45:59.990 回答
0

我会扩展我的枚举类型的空间,如下所示:

/* UNTESTED */
struct MyType {
 enum e { type1, type2, type3, max_type = type3, _big = max_type+256 };

 /** Acceptable values are 0-255 */
 static e UserType(int i) { return e(max_type + 1 + i); }
};

void f (MyType::e t) {}

int main () {
  f(MyType::type1);
  f(MyType::UserType(47));
  enum UserEnum { utype1, utype2, utype3 };
  f(MyType::UserType(utype3));
}
于 2012-08-10T16:49:11.113 回答
0

你不能用枚举来做,但你可以定义一个新的类型。

c++ 枚举与类大致相同:

struct Enum
{
  int value;
  explicit Enum(int v) : value(v) {}
  operator int () {return value;}
};

static const Enum value_1 = Enum(1);
static const Enum value_2 = Enum(2);
...

嗯,它不完全一样,有一些区别,比如你不能从枚举继承,而枚举是整数类型,所以你可以将 int 转换为枚举,但这些差异不大。

如果你这样做,那么你可以通过简单地添加新常量来向“枚举”添加新值。

static const Enum custom_value_1 = Enum(100);
static const Enum custom_value_2 = Enum(200);

您需要制作它们static,因为 C++ 很愚蠢,并且即使它们可以用作编译时常量也会分配资源。的替代方法static是将它们放入匿名命名空间中:

namespace
{
  const Enum custom_value_1 = Enum(100);
  const Enum custom_value_2 = Enum(200);
}

如果您不执行其中一项操作,您将收到链接器错误。此方法将为您提供与枚举获取相同类型的类型检查,并且您可以在单独的头文件中扩展值。

于 2012-08-10T17:07:53.973 回答