Как кодировать встроенную взаимную абстракцию в C ++? - PullRequest
1 голос
/ 23 марта 2009

Пример первый:

template <class HashingSolution> 
struct State : public HashingSolution {

  void Update(int idx, int val) {
    UpdateHash(idx, val);
  }

  int GetState(int idx) {
    return ...;
  }
};

struct DummyHashingSolution {
  void UpdateHash(int idx, int val) {}
  void RecalcHash() {}
};

struct MyHashingSolution {
  void UpdateHash(int idx, int val) {
    ...
  }

  void RecalcHash() {
    ...
    UpdateHash(idx, GetState(idx)); // Problem: no acces to GetState function, can't do recursive application of templates
    ...
  }
};

В этом примере я могу передать MyHashingSolution классу State, чтобы у State был доступ к методам HashingSolution, но HashingSolution не может вызвать GetState. Можно ли обойти это?

Это самый глубокий цикл. Виртуальная функция здесь снижает производительность более чем на 25%. Встраивание важно для меня.

Ответы [ 2 ]

5 голосов
/ 23 марта 2009

Как предполагает Джалф в комментариях, вы, вероятно, захотите использовать вариант любопытно повторяющегося шаблона (CRTP). То есть, сделать MyHashingSolution шаблоном класса, параметризованным производным классом:

template <typename D>
struct MyHashingSolution {
    typedef D Derived;

    void UpdateHash(int idx, int val) {
        ...
    }

    void RecalcHash() {
        ...
        UpdateHash(idx, derived().GetState(idx));
        ...
    }

private:
    // Just for convenience
    Derived& derived() { return *static_cast<Derived*>(this); }
};

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

template <template <class T> class HashingSolution>
struct State : public HashingSolution<State<HashingSolution> > {
typedef HashingSolution<State<HashingSolution> > Parent;

    void Update(int idx, int val) {
        Parent::UpdateHash(idx, val);   // g++ requires "Parent::"
    }

    int GetState(int idx) {
        return ...;
    }
};

Ключевым моментом является то, что при условии, что State наследуется от HashingSolution<State<HashingSolution> >, Derived является производным классом HashingSolution<State<HashingSolution> >, поэтому static_cast<Derived*>(this) downcast в HashingSolution<State>::derived() компилируется и работает правильно. (Если вы запутаетесь и извлечете State из HashingSolution<SomeOtherType> вместо этого, а затем попробуете что-то, связанное с вызовом derived(), компилятор будет жаловаться, поскольку требования для static_cast<> не выполнены.)

Затем объявите конкретный класс State, который вы хотите использовать, следующим образом:

typedef State<MyHashingSolution> MyState;

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

0 голосов
/ 23 марта 2009

Как выстрел в темноте, учитывая почти полное отсутствие информации в вопросе (см. Комментарии): будут ли полезны шаблоны? Они часто хороши для полиморфизма во время компиляции.

Чтобы получить больше потенциально полезной информации, пожалуйста, объясните проблему подробнее. Посмотрите на комментарии к проблеме. Скажите нам, почему вы знаете, какие микрооптимизации необходимо выполнить, когда вы все еще работаете над фундаментальным дизайном. Если в средах компиляции или выполнения есть что-то не связанное с мейнстримом, сообщите нам несколько подробностей.

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