Я хочу внедрить имя для функции, которая будет создана с довольно фиксированной сигнатурой, в базовый класс CRTP (CURLYURURRURING Template Pattern).
Вот мой действующий существующий код ( coliru MCVE link ): -
#include <iostream>
#include <string>
//--- library layer ---
template<class O,class Under> struct Crtp{
Under* oNo=nullptr;
auto getUnderlying(){
return oNo;
}
};
//--- user layer ex 1 ---
struct B{ // please don't edit this class
int k=0;
};
struct BO : Crtp<BO,B>{
auto getBOUn(){ return Crtp<BO,B>::getUnderlying();}
// some other functions
};
//--- user layer ex 2 ---
struct C{ // please don't edit this class
int kad=0;
};
struct CO : Crtp<CO,C>{
auto getCOUn(){ return Crtp<CO,C>::getUnderlying();}
// some other functions
};
int main() {
BO bo; B b; bo.Crtp<BO,B>::oNo=&b; //<-- please don't edit
std::cout<< bo.getBOUn()->k;
}
I wi sh это будет просто как: -
//--- user layer ex 1 ---
struct B{ // (same)
int k=0;
};
struct BO : Crtp<BO,B,getBOUn>{ //<--- so easy and clean
// some other functions
};
Возможно ли это, как?
У меня> 100 пар классов, таких как B
& BO
; у них есть свои собственные уникальные пользовательские имена для getBOUn()
-подобной функции.
Я могу исправить это с помощью макроса, но я не хочу другого слоя беспорядка.
Пожалуйста, не отвечайте с помощью макроса.
Реальные варианты использования
Я часто создаю классы, подобные этому: -
struct Walkable{
float stamina =0 ;
float speed =0;
};
struct WalkableO: Crtp<WalkableO,Walkable>{
auto getWalkUnderlying(){ return Crtp<BO,B>::getUnderlying();}
void runNow(){
if(getWalkUnderlying()->stamina >1 ){
getWalkUnderlying()->speed +=3;
getWalkUnderlying()->stamina --;
}
}
};
class Dog : public virtual WalkableO, public virtual HasHpO, public virtual EatenableO {};
Иногда мне нравится получать доступ к определенным c базовым напрямую: -
Dog* dogPtr; /** some ini ...*/ dogPtr->getWalkUnderlying()->stamina=10;
Иногда я хочу получить доступ к "некоторым другим функциям" более абстрактным способом: -
dogOPtr->runNow(); //a custom function within WalkableO
Я использую виртуальное наследование потому что если я изменю дизайн, чтобы, например, каждые WalkableO
до были HasHpO
, я могу просто отредактировать код, как показано ниже.
Мне даже не нужно изменять Dog
код : -
struct WalkableO: Crtp<WalkableO,Walkable>, virtual HasHpO{/*something*/};
Dog
само по себе, может быть базовым классом для BullDog
, TigerDog
, et c.