Экземпляры подсчета ссылок классов на основе их типов - PullRequest
1 голос
/ 30 мая 2011

Рассмотрим следующий код:

struct I
{
    SomeInternalState m_internalState;
};

struct S
{
    I * m_i;
    set_I (I * i)
    {
        m_i = i;
        makeSomeChangesToTheInternalStateOfI(m_i);
    }
};

struct S_1 : S { ... };
struct S_2 : S { ... };
...
struct S_n : S { ... };

Дано, что может быть создано произвольное количество экземпляров S_1, ... S_n, и все они вызовут set_I()только один раз.

Теперь я хочу, чтобы экземпляры от S_1, ... S_n до makeSomeChangesToTheInternalStateOfI() только один раз для экземпляра I для типа S_x, чтобы я мог вызывать set_I() из разных экземпляров одного и того же класса S_x с одинаковым экземпляром I и быть уверенным, что внутреннее состояние I будет изменено только во время первого вызова.

Вероятное решение - поместить некоторую таблицу диспетчеризации в I, но я не могу придумать разумного ключа для нее, основанной исключительно на типе S_x экземпляра и не связанной с каким-либо рукописным "типом среды выполненияid "константы для всех возможных типов S_1, ... S_n.

Как мне это сделать?

РЕДАКТИРОВАТЬ:

Точки, которые я должен был подчеркнуть:

1) Может быть более одного экземпляра I одновременно, и классы S_xВы сможете изменить состояние нескольких экземпляров I, но только один раз для каждого экземпляра.То есть:

I i1, i2;
S_1 s1a, s1b;
S_2 s2a, s2b;

// all possible combinations:
s1a.changeStateOfI(i1);
s1b.changeStateOfI(i1);
s2a.changeStateOfI(i1);
s2b.changeStateOfI(i1);
s1a.changeStateOfI(i2);
s1b.changeStateOfI(i2);
s2a.changeStateOfI(i2);
s2b.changeStateOfI(i2);

В этом фрагменте состояния как i1, так и i2 должны изменяться только один раз методом S_1 (через s1a) и один раз S_2 (через s2a).

2) Полагаю, для решения проблемы можно использовать подсчет ссылок - нет необходимости точно знать, сколько раз происходила инициализация, достаточно знать, была ли она или нет.

EDIT2

Я отметил нм в качестве ответа, хотя мое окончательное решение немного отличается.Вот так, чтобы другие тоже могли его использовать:

struct AbstractS
{
    I * m_i;
    virtual void set_I (I * i) = 0;
};


template <typename self_T>
struct RegS : AbstractS
{
    static std::set<I *> s_registeredContexts;

    virtual void set_I (I * i)
    {
        m_i = i;

        if (i == NULL || s_registeredContexts.count(i) > 0) return;

        makeSomeChangesToTheInternalStateOfI(i);
        contexts.insert(i);
    }
};

template <typename self_T>
std::set<I *> InterpreterState<self_T>::s_registeredContexts;


struct S_1 : RegS<S_1> { ... };
struct S_2 : RegS<S_2> { ... };
...
struct S_n : RegS<S_n> { ... };

Разница по сравнению с вариантом nm заключается в том, что я использовал здесь шаблон CRTP вместо перечисления экземпляровто, чего я тоже хотел избежать.

Ответы [ 2 ]

2 голосов
/ 30 мая 2011

Вы можете использовать typeinfo в качестве ключа, но это плохая идея.Вы не должны считать типы в вашей программе.Позвольте мне объяснить на простом примере.

Допустим, у вас есть тип Vehicle и его потомки Car, Truck и Bike.Вы вызываете свою функцию один раз для каждого из этих классов.Все идет нормально.Теперь вам нужно, по совершенно не связанной причине, обрабатывать внедорожники, RacingCars, GarbageTrucks, Trikes, RedCars, ReddishCars и YellowishReddishWithGreenishTintCars.Ваше решение о том, сколько раз ваша функция будет вызываться, должно быть полностью ортогонально вашему решению о введении или отсутствии введения отдельных классов для каждого из этих случаев.

Таким образом, вам нужно что-то, чтобы пометить ваши Транспортные средства как отличные или похожие, исключительно для того, чтобы вызывать вашу функцию один раз для группы похожих объектов.Один из способов добиться этого - использовать шаблон класса и набор параметров типа (любой тип параметров).

class ChangerOfInternalStateOfI
{
  public:
    ChangerOfInternalStateOfI (I* i) { 
      makeSomeChangesToTheInternalStateOfI(i); 
    }
};

template <int n>
class S_N : public S
{
  public:
    S_N() {
       static ChangerOfInternalStateOfI changer;
    }
};

typedef S_N<1> S_1;
typedef S_N<2> S_2;

Вы можете использовать enum вместо int или typename, это не имеет значения,Дело в том, что все ваши ChangerOfInternalStateOfI различны, потому что они принадлежат разным классам, и каждый из конструкторов будет вызван один раз.

1 голос
/ 01 июня 2011

Если путь со статическим элементом данных n.m. , упомянутый не соответствует цели, как насчет того, чтобы набор, содержащий типы, обработанные ранее в I?
Поскольку type_info сам по себе не менее чем сопоставим, простая обертка type_info_ используется в следующем коде. Если проверка типа должна быть сделана полиморфно (через базовый класс S), Информация о типе времени выполнения необходима. Итак, я сделал changeStateOfI be virtual.

#include <typeinfo>
#include <set>
using namespace std;

struct type_info_ {
  type_info const *t;
  type_info_( type_info const* t ) : t( t ) {}
  bool operator<( type_info_ const& x ) const { return t->before( *x.t ); }
};

struct I {
  set< type_info_ > types;

  void f( type_info const& t, char const* s ) {
    if ( types.insert( type_info_( &t ) ).second ) { puts( s ); }
  }
};

struct S {
  virtual void changeStateOfI( I& i, char const* s ) {
    i.f( typeid( *this ), s );
  }
};

struct S_1 : S {};
struct S_2 : S {};

int main() {
  I i1, i2;
  S_1 s1a, s1b;
  S_2 s2a, s2b;
  s1a.changeStateOfI(i1, "s1a i1");
  s1b.changeStateOfI(i1, "s1b i1");
  s2a.changeStateOfI(i1, "s2a i1");
  s2b.changeStateOfI(i1, "s2b i1");
  s1a.changeStateOfI(i2, "s1a i2");
  s1b.changeStateOfI(i2, "s1b i2");
  s2a.changeStateOfI(i2, "s2a i2");
  s2b.changeStateOfI(i2, "s2b i2");
}

Вышеуказанный код напечатан s1a i1, s2a i1, s1a i2, s2a i2 в моем окружении.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...