Как закодировать встроенную взаимную абстракцию на C++?

StackOverflow https://stackoverflow.com/questions/673491

  •  21-08-2019
  •  | 
  •  

Вопрос

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

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%.Для меня инлайнинг имеет решающее значение.

Это было полезно?

Решение

Как предполагает Джалф в комментариях, вы, вероятно, захотите использовать вариант Любопытно повторяющийся шаблон шаблона (ЦРТП).То есть сделать 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) подавленный в HashingSolution<State>::derived() компилируется и работает корректно.(Если вы ошибетесь и получите State от HashingSolution<SomeOtherType> вместо этого, а затем попробуйте что-нибудь, что включает в себя вызов derived(), компилятор будет жаловаться, поскольку требования к static_cast<> не встречаются.)

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

typedef State<MyHashingSolution> MyState;

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

Другие советы

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top