Как закодировать встроенную взаимную абстракцию на C++?
-
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
(и любые другие подобные типы) к шаблонам, которые игнорируют свой единственный аргумент шаблона, чтобы их можно было использовать в качестве аргументов шаблона шаблона.
Другие советы
Как выстрел в темноте, учитывая практически полное отсутствие информации в вопросе (см. комментарии):будут ли шаблоны полезны?Они часто хороши для полиморфизма во время компиляции.
Чтобы получить больше потенциально полезной информации, пожалуйста, объясните проблему подробнее.Посмотрите комментарии к проблеме.Расскажите нам, почему вы знаете, какие микрооптимизации необходимо выполнить, когда вы все еще работаете над фундаментальным проектированием.Если есть что-то необычное в средах компиляции или выполнения, дайте нам несколько подробностей.