【问题标题】:inject a custom function-name with a fixed signature into CRTP将具有固定签名的自定义函数名称注入 CRTP
【发布时间】:2020-02-03 04:31:10
【问题描述】:

我想将具有相当固定签名的待创建函数的 名称 注入到 CRTP(Curiously recurring 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; 
}

我希望它会像这样简单:-

//--- user layer ex 1 ---
struct B{  // (same)
    int k=0;
};
struct BO : Crtp<BO,B,getBOUn>{  //<--- so easy and clean
    // some other functions
};

有可能吗,怎么做?

我有 >100 个类对,例如 BBO ;他们对getBOUn()-like 函数有自己独特的自定义名称。

我可以用宏来修复它,但我不想要另一层混乱。
请不要使用宏回答。

真实用例

我经常创建这样的类:-

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 {};

有时,我喜欢直接访问特定的底层:-

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 本身,可以是BullDogTigerDog 等的基类

【问题讨论】:

  • 为什么你需要在BO 中调用getUnderlying 的函数?为什么不直接使用getUnderlying,省去很多麻烦呢?否则,CRTP 基础有点毫无意义。
  • “底层”指针的用途是什么?你在实施 pimpl 成语吗?如果是这样,我相信你能想出比CrtpgetUnderlying 更好的名字。
  • @Kerndog73 感谢您提出的好问题。我在我的帖子中回答它,因为这是我应该告诉的信息。我正在实现一个公共实现(与 pimpl 类似但不同)。
  • 现在我明白了!你听说过实体-组件-系统架构吗?我为最好的 C++ ECS 框架之一做出了贡献(在我的书中,它是最好的),即EnTT。我强烈建议您查看 EnTT!您可以加入the Gitter chatroom与专家讨论EnTT。
  • @Kerndog73 哈,是的,我正在开发一个 ECS 库并将其用于我的游戏。感谢您的链接。

标签: c++ templates c++17 crtp


【解决方案1】:

很遗憾,您声明新函数的选择非常有限。

在这种情况下,您将引入一个新的identifier。在preprocessing 之后,标识符 只能由declaration 引入。在您的限制下,只有三种相关的声明simple-declarations、function-definitions 和template-declarations(在声明之上,它在这种情况下必须是 simple-declarationfunction-definition 因为它应该声明一个函数)。在 template-declaration 中,您声明的唯一名称是在底层 simple-declarationfunction- 中声明的名称定义,所以我们基本上仅限于simple-declarations和function-definitions。 simple-declarationfunction-definition 引入的名称在其declarators 中指定,因此无法指定新的标识符 并自动声明它。

换句话说,在 C++ 中进行预处理之后,无法“透明地”传递要声明的标识符。所以我不认为你想要做的事情是可能的。你必须要么使用宏,要么自己声明函数。

【讨论】:

  • 不幸的是,这个答案可能是我需要听到的。谢谢。
  • @cppBeginner 你可以试试 EnTT。正如 Kerndog73 提到的,这是一个非常好的库
  • @Sneaky Turtle :: 我之前曾预览过那个很棒的库。 AFAIK,这个问题不能由 EnTT 解决。我非常喜欢面向对象,并希望有一种优雅的方式将 OO 与 ECS 结合起来。部分幸运的是,宏可以优雅地混合它。
  • @cppBeginner OO 和 ECS 不能混合使用。他们几乎是对立的。恕我直言,正确完成的 ECS 比 OO 优雅得多。如果我说实话,问题中的代码并不优雅。也许你可以问一个关于你在 EnTT 上遇到的问题的问题?
  • @Sneaky Turtle 哈哈,是的,这可能只是我自己的信念。我以某种方式在另一个 SO 问题中问了它——他们回答“不要这样做!”。
猜你喜欢
  • 2011-05-11
  • 1970-01-01
  • 1970-01-01
  • 2018-11-02
  • 2011-01-24
  • 1970-01-01
  • 2014-06-14
  • 1970-01-01
  • 2017-05-11
相关资源
最近更新 更多