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カスタムイベント名を要求するか、単に文字列を使用することが含まれますが、どちらも最適ではないようです.

これに対する一般的な解決策はありますか?

1 つの提案はstruct EventType、列挙型で指定された範囲内の値を返すために a を使用することです。ただし、これによりコンパイラの安全性の問題は解決されますが、名前付きの型を追加する問題は解決されません。ユーザーはこれらをグローバル スコープに追加する必要があります。

前者の問題ではなく後者に対処する 1 つの可能性は、EventType を整数型に typedef し、カスタム型をライブラリの名前空間または独自の名前空間に追加することをユーザーに任せることです。一意の値を提供するファクトリ メソッドは、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

あなたの最善の策は、単にイベント型を通常の整数型として取り、列挙型を使用して組み込み型を定義し、ユーザー定義の最小値と最大値を提供し、その間にユーザーが独自の整数値を作成することだと思います列挙子。次に、アサーションを使用して、基本イベントが不明なイベント タイプを処理しようとしないようにします。

EDIT:子クラスが後で再び選択するためのデータを保持している場合を除き、理解できるタイプと理解できないタイプを持つベースイベントクラスは壊れやすい可能性があることに注意してください。その場合でも、別のデザインを検討したほうがよいかもしれません。設定後のイベント タイプの使用方法について詳しく教えてください。

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

enum ではできませんが、新しい型を定義できます。

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);

staticC++ は愚かで、コンパイル時の定数として使用できる場合でもリソースを割り当てるため、作成する必要があります。に代わる方法はstatic、それらを匿名の名前空間に配置することです。

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

これらのいずれかを行わないと、リンカー エラーが発生します。このメソッドは、同じタイプの型チェック列挙型 get を提供し、個別のヘッダー ファイルで値を拡張できます。

于 2012-08-10T17:07:53.973 に答える