通过继承和模板进行Static_pointer_cast

static_pointer_cast through inheritance and template

本文关键字:Static pointer cast 继承      更新时间:2023-10-16

我很难找到以下错误的修复,在编译std::static_pointer_cast<>()时抛出:

error: invalid static_cast from type ecse::EventSubscriptionManager<ecse::BaseEvent>* to type ecse::EventSubscriptionManager<TestEvent>*

我有以下层次结构。最后,它们将被POD类型成员填充,并且很可能成为结构体。

class BaseEvent {};
template <class E>
class Event : public BaseEvent, public Type<E> {};
class TestEvent : public Event<TestEvent> {};

我目前正在EventManager的订阅功能部分工作,但是在编译时,我收到上面发布的错误。注:E::ID()在类中定义为Type,用于标识类类型。

template <class E>
class EventSubscriptionManager
{
public:
  void Subscribe(std::function<void(E)>  fptr);
private:
  std::function<void(E)> event_function_;
};
class EventManager
{
public:
  template <class E>
  void Subscribe(std::function<void(E)> fptr)
  {
     std::shared_ptr<EventSubscriptionManager<E>> sub_manager_ptr;
     auto sub_manager_iterator = sub_managers_.find(E::ID());
     if(sub_manager_iterator == sub_managers_.end())
     {
       sub_manager_ptr = std::make_shared<EventSubscriptionManager<E>>();
     }
     else
     {
       sub_manager_ptr = std::static_pointer_cast<EventSubscriptionManager<E>>(sub_manager_iterator->second);
     }
     // Continue function...
  }
private:
  std::unordered_map<std::size_t, std::shared_ptr<EventSubscriptionManager<BaseEvent>>> sub_managers_;
}

我认为问题是在TestEventBaseEvent之间有一个具有模板的Event<E>类,TestEvent继承Event<TestEvent>而不是BaseEvent。这是真的吗?如果是这样,我该如何设置层次结构以允许这种类型的强制转换?

如果不是这样,那么上述静态强制转换的问题是什么?

我可以告诉你为什么它不能编译。这是因为

EventSubscriptionManager<E>

无关
EventSubscriptionManager<BaseEvent>

因此,根据参考页上的第1点,

static_cast<EventSubscriptionManager<E>*>((EventSubscriptionManager<BaseEvent>*)nullptr)

是不规范的。

然而,在不了解背景的情况下,我不知道该怎么做。只是:你必须把这两个类联系起来,或者选择一个全新的设计。



为了做到这一点,这里有一个最小的例子,为什么它会失败,这可能是有帮助的:
struct Base {};
struct Derived : Base {};
template<typename T>
struct Foo {};
int main()
{
   static_cast<Foo<Derived>*>((Foo<Base>*)nullptr);
}

你可以试着改进一下。

在c++中,没有协方差和逆方差,T<Base>T<Sub>之间没有关系,即使BaseSub之间有关系。

你需要为不同的EventSubscriptionManager实例(例如:EventSubscriptionManagerBase)建立一个共同的祖先,并使用它,或者提供一个转换构造函数。