У меня есть следующая программа, аналогичная моей кодовой базе. Класс FunctionState, который выполняет какой-то алгоритм (потенциально в нескольких потоках) и класс Function, который контролирует использование классов FunctionState и может выполнять некоторые операции установки/удаления алгоритма.Как я могу использовать CRTP для удаления виртуального метода в этом контексте?
#include <iostream>
#include <vector>
class FunctionState;
class Function {
public:
virtual FunctionState* NewFunctionState() = 0;
protected:
std::vector<FunctionState*> states;
};
class FunctionState {
public:
FunctionState(Function* func) : mFunc(func) {}
virtual void RunState() = 0;
void ExecuteFunctionLotsAndLotsOfTimes();
private:
Function* mFunc;
};
#define VERY_BIG_NUMBER 10
void FunctionState::ExecuteFunctionLotsAndLotsOfTimes() {
for(int i = 0; i < VERY_BIG_NUMBER; ++i) {
RunState();
}
};
class PrintFunction : public Function {
FunctionState* NewFunctionState();
};
class PrintFunctionState : public FunctionState {
public:
PrintFunctionState(PrintFunction* func) : FunctionState(func) {}
void RunState() override {
std::cout << "in print function state" << '\n';
}
};
FunctionState* PrintFunction::NewFunctionState() {
FunctionState* state = new PrintFunctionState(this);
states.push_back(state);
return state;
}
class AddFunction : public Function {
FunctionState* NewFunctionState();
};
class AddFunctionState : public FunctionState {
public:
AddFunctionState(AddFunction* func) : FunctionState(func), x(0) {}
void RunState() override {
++x;
}
private:
int x;
};
FunctionState* AddFunction::NewFunctionState() {
FunctionState* state = new AddFunctionState(this);
states.push_back(state);
return state;
}
int main() {
Function* func = new PrintFunction();
Function* func2 = new AddFunction();
std::vector<Function*> vec = {func, func2};
for(auto& func : vec) {
func->NewFunctionState()->ExecuteFunctionLotsAndLotsOfTimes();
}
return 0;
}
Теперь я профилированный мой код, и увидел, что есть точка доступ в FunctionState :: ExecuteFunctionLotsAndLotsOfTimes(). Проблема в том, что эта функция повторяется много раз и вызывает RunState(), виртуальную функцию в классе FunctionState. Там я выполняю много операций, которые потенциально могут вывести указатели vtable из кеша L1, в результате чего кеш L1 пропускает каждую итерацию цикла.
Поэтому я хочу удалить необходимость в виртуальном вызове. Я решил, что хороший способ сделать это был с CRTP. Класс FunctionState будет принимать параметр шаблона типа реализующего его класса и называть его соответствующим методом, при этом виртуальный вызов RunState() не требуется.
Теперь, когда я пытался сделать переместить его в CRTP, я столкнулся с некоторыми проблемами с классом функций:
- Как я вперед объявить класс FunctionState (как это шаблонный сейчас)?
Должен ли я добавить параметр шаблона в класс Function?
3. Какова была бы конструкция объекта Function, если я его шаблон? Как удалить необходимость в классах, которые используют объект Function для указания параметра типа?
Пожалуйста, обратите внимание, что это всего лишь тривиальный вариант моей реальной кодовую. Реальная кодовая база - 10 К + строк кода (не неуправляемая, но полного переписывания не может быть и речи).
Также, если есть другой способ удалить виртуальный вызов RunState(), который не включает CRTP, тогда это также будет оценено.
Моя попытка использовать CRTP:
#include <iostream>
#include <vector>
class Function;
template<class T>
class FunctionState {
public:
FunctionState(Function* func) : mFunc(func) {}
void RunState() {
static_cast<T*>(this)->RunState();
};
void ExecuteFunctionLotsAndLotsOfTimes();
private:
Function* mFunc;
};
class Function {
public:
virtual FunctionState* NewFunctionState() = 0;
protected:
std::vector<FunctionState*> states;
};
#define VERY_BIG_NUMBER 10
template <typename T>
void FunctionState<T>::ExecuteFunctionLotsAndLotsOfTimes() {
for(int i = 0; i < VERY_BIG_NUMBER; ++i) {
RunState();
}
};
class PrintFunctionState;
class PrintFunction : public Function {
PrintFunctionState* NewFunctionState();
};
class PrintFunctionState : public FunctionState<PrintFunctionState> {
public:
PrintFunctionState(PrintFunction* func) : FunctionState<PrintFunctionState>(func) {}
void RunState() {
std::cout << "in print function state" << '\n';
}
};
PrintFunctionState* PrintFunction::NewFunctionState() {
PrintFunctionState* state = new PrintFunctionState(this);
states.push_back(state);
return state;
}
class AddFunctionState;
class AddFunction : public Function {
AddFunctionState* NewFunctionState();
};
class AddFunctionState : public FunctionState<AddFunctionState> {
public:
AddFunctionState(AddFunction* func) : FunctionState<AddFunctionState>(func), x(0) {}
void RunState() {
++x;
}
private:
int x;
};
AddFunctionState* AddFunction::NewFunctionState() {
AddFunctionState* state = new AddFunctionState(this);
states.push_back(state);
return state;
}
int main() {
Function* func = new PrintFunction();
Function* func2 = new AddFunction();
std::vector<Function*> vec = {func, func2};
for(auto& func : vec) {
func->NewFunctionState()->ExecuteFunctionLotsAndLotsOfTimes();
}
return 0;
}
_ «Теперь, когда я попытался переместить его в CRTP ...» _ Можете ли вы показать нам вашу точную попытку, пожалуйста? –
Добавил мою попытку, она не компилируется из-за проблем с использованием FunctionState без аргумента шаблона. – Andrew
Ну, вам нужен аргумент шаблона при создании экземпляра класса шаблона. В случае CRTP - производный класс. И что? –