внедрить пользовательское имя функции с фиксированной подписью в CRTP - PullRequest
2 голосов
/ 03 февраля 2020

Я хочу внедрить имя для функции, которая будет создана с довольно фиксированной сигнатурой, в базовый класс 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.

1 Ответ

5 голосов
/ 05 февраля 2020

К сожалению, ваш выбор для объявления новой функции весьма ограничен.

В этом случае вы вводите новый идентификатор . После предварительной обработки идентификатор может быть введен только посредством объявления . В соответствии с вашими ограничениями, только три соответствующих типа декларации s: simple-декларация s, определение функции s и шаблон объявления с (поверх объявления , которое должно быть simple-объявлением или определение-функции в этом случае, поскольку оно должно объявлять функцию). В объявлении шаблона единственное (ые) имя (и), которое вы объявляете, это (ые) имена (имена), объявленные в базовом simple-объявление или определение функции , поэтому мы в основном ограничены простым объявлением с и определением функции с. Имена, введенные с помощью простого объявления или определения функции , указаны в его деклараторе с, поэтому нет возможности задайте новый идентификатор и автоматически объявите его.

Другими словами, нет способа передавать «объявленные» идентификаторы вокруг «прозрачно» после предварительной обработки в C ++. Поэтому я не думаю, что вы пытаетесь сделать это возможно. Вы должны либо использовать макрос, либо объявить функции самостоятельно.

...