简体   繁体   中英

static_pointer_cast through inheritance and template

I am having trouble finding a fix for the following error, thrown when compiling a std::static_pointer_cast<>() :

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

I have the following hierarchy. In the end they will be filled with POD type members and will most likely become structs.

class BaseEvent {};

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

class TestEvent : public Event<TestEvent> {};

I am currently working on the Subscribe function part of the EventManager, however when compiling I am receiving the error posted above. Note: E::ID() is defined in the class as Type and is used for identifying the class 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_;
}

I believe that the issue is that between the TestEvent and the BaseEvent there is the Event<E> class with the template, with TestEvent inheriting Event<TestEvent> instead of BaseEvent . Is this true? If so, how can I set up my hierarchy to allow for this type of casting?

If that is not the case, what is the issue with the above static cast?

In C++, there is no covariance or contravariance, there is no relationship between T<Base> and T<Sub> , even if there is one between Base and Sub .

You either need to build a common ancestor of different EventSubscriptionManager instances (eg: EventSubscriptionManagerBase ), and use that, or provide a converting constructor.

I can tell you why it does not compile. This is because

EventSubscriptionManager<E>

is unrelated to

EventSubscriptionManager<BaseEvent>

So, according to point 1.) on the reference page,

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

is ill-formed.

However, without knowing the background I can't tell what to do as a workaround. Just: you have to relate the two classes, or choose a completely new design.



In order to do so, here is a minimal example why it fails which might be helpful:

struct Base {};
struct Derived : Base {};

template<typename T>
struct Foo {};

int main()
{
   static_cast<Foo<Derived>*>((Foo<Base>*)nullptr);
}

You can try to improve on that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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