gpt4 book ai didi

c++ - 从模板函数中缓存一个基类型以在 std::is_base_of 中使用

转载 作者:太空狗 更新时间:2023-10-29 22:54:46 28 4
gpt4 key购买 nike

我想创建一个库:-

  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
}

怎么做?

我糟糕的解决方案

方案一:std::is_base_of

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

解决方案 2 ( MCVE demo ):虚拟析构函数 + 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 final,通过派生类做批量删除,但有些地方不合适,不方便。
  • 我必须创建 Bx 的实例仅用于 dynamic_cast 检查。
    如果它的构造函数做了一些特殊的事情,这可能会导致一些复杂情况。

有没有更好的办法?

最佳答案

您能否要求您的用户指定一组允许的 Base 类型?在这种情况下,任务变得简单(online demo):

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.

关于c++ - 从模板函数中缓存一个基类型以在 std::is_base_of<Here!,> 中使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54320138/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com