繁体   English   中英

从模板函数缓存基类型以在std :: is_base_of中使用<Here!,>

[英]cache a Base type from template function to use in std::is_base_of<Here!,>

我想创建一个库: -

  1. 用户通过addCallback<Base>(Callback* callback)添加回调(通常在第一个时间步)
  2. 后来,通常在不同的.cpp ,每当用户调用actor<Bx>()

    • 如果Bx继承自Base ,则调用callback->callback()
    • 别无所求
  3. (信息)我确信每个Bx总是从A继承。

这是初始代码: -

#include <iostream>
class A{};
class Callback{
     public: virtual void callback()=0; 
};
template<class Base> void addCallback(Callback* callback){  
    //???
};
template<class Bx> void actor(){
    //???
}
//^^^^^^ my library end here

class B : public A{};
class B1 : public B{};
class C : public A{};
class CallbackCustom1: public Callback{
    public: virtual void callback(){std::cout<<"A"<<std::endl;}
};
class CallbackCustom2: public Callback{
    public: virtual void callback(){std::cout<<"B"<<std::endl;}
};
int main(){
    CallbackCustom1 call1;
    CallbackCustom2 call2;
    addCallback<A>(&call1); 
    addCallback<B>(&call2); 
    //vvv  below is usually in another .cpp
    actor<B1>(); // should print "A" and "B"
    actor<C>(); // should print "A" only
}

怎么做?

我糟糕的解决方案

解决方案1:std :: is_base_of

我真的很喜欢使用std::is_base_of<Base,Derive>
但是,这是不可能的,因为为方便起见,用户只想在actor<Bx>()调用单个类型Bx
std::is_base_of需要两个类的名称而不是一个。

解决方案2( MCVE演示 ):虚拟析构函数+ std :: function

它可以进行更多优化,但我想保持简单: -

#include <iostream>
#include <functional>
class A{public: virtual ~A()=default; };
class Callback{
     public: virtual void callback()=0; 
};
class MyTuple{public:
    std::function<bool(A*)> func;
    Callback* callback;
};
std::vector<MyTuple> myTuples;
template<class Base> void addCallback(Callback* callback){  
    std::function<bool(A*)> func=
        [](A* a){return dynamic_cast<Base*>(a)!=nullptr;};
    MyTuple tuple; tuple.func=func; tuple.callback=callback;
    myTuples.push_back(tuple);
}
template<class Bx> void actor(){
    Bx b;
    for(auto tuple:myTuples){
        if(tuple.func(&b)){
            tuple.callback->callback();
        }
    }
}
//^^^^^^ my library end here

它有效,但有一些缺点: -

  • 我必须向A添加虚拟析构函数以使其具有多态性 我觉得这是一个讨厌的黑客。
  • 在我的游戏中,在某些时间步骤中, A::~A()可能被称为每秒100,000次。
    我可以通过使B1C 最终并通过派生类进行批量删除来降低成本,但在某些地方,它是不合适和不方便的。
  • 我必须为dynamic_cast检查创建Bx实例。
    如果构造函数执行特殊操作,这可能会导致一些复杂化。

有没有更好的方法?

您是否可以要求您的用户指定允许的Base类型集? 在这种情况下,任务变得简单( 在线演示 ):

static_assert(__cplusplus >= 201703L, "example for C++17, but C++14 possible");

#include <iostream>
#include <type_traits>
#include <vector>

struct Callback {
  virtual void callback() = 0;
};

template<class... RegisteredBases>
struct CallbackSystem {

  template<class Base>
  static auto& callbacks_for() {
    static std::vector<Callback*> callbacks_for_base_{};
//
// For each `Base`, the callbacks are stored in a different vector.
// This way, we can avoid the in-loop branch (see `actor_impl`).
//
// TODO: consider performance cost of bad memory locality (can be
// improved if necessary).
//
    return callbacks_for_base_;
  }

  template<class Base>
  static void addCallback(Callback* callback) {
    static_assert((... || std::is_same<Base, RegisteredBases>{}));
    callbacks_for<Base>().push_back(callback);
  }

  template<class Derived, class RegisteredBase>
  static void actor_impl() {// called from `actor` for each RegisteredBase
    if(std::is_base_of<RegisteredBase, Derived>{}) {// branch outside loop
      // if `RegisteredBase` matches then process all its callbacks
      for(Callback* callback : callbacks_for<RegisteredBase>()) {
        callback->callback();
      }
    }
  }

  template<class Derived>
  static void actor() {
    (actor_impl<Derived, RegisteredBases>(), ...);
  }
};

允许的Base类型注册如下:

using MyCallbacks = CallbackSystem<A, B> {};

用法如下:

MyCallbacks::addCallback<A>(&call1);
MyCallbacks::addCallback<B>(&call2);
// MyCallbacks::addCallback<B1>(&call2);// compile error (good)


//vvv  below is usually in another .cpp
std::cout << R"(should print "A" and "B":)" << std::endl;
MyCallbacks::actor<B1>();

std::cout << R"(should print "A" only:)" << std::endl;
MyCallbacks::actor<C>();

或者,可以以相反的方式设计API:可以要求用户指定允许作为actor的模板参数的所有类,而不是限制Base类。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM