C 模板在结构中类型

C++ Template type inside a structure

本文关键字:类型 结构      更新时间:2023-10-16

这是我的消息结构:

struct tEventMessage 
{
    // Type of the event
    int Type;
    // (void*) Allows those to be casted into per-Type objects
    void *pArgument1;   
    void *pArgument2;
};

我可以在此结构中添加某种"模板"成员,以便稍后在构建消息时,我可以将这些指针 和我希望的任何其他数据传递?(请参阅下面的示例)

struct tEventMessage 
{
    // Type of the event
    int Type;
    // (void*) Allows those to be casted into per-Type objects
    void *pArgument1;   
    void *pArgument2;
    // Template
    T tSomeTemplateMember;
};
 void HandleClick(....)
 {
 CVector3 vNewPosition = ....
 tEventMessage _msg;
 _msg.Type = xxxx;
 _msg.pArgument1 = pA->GetObjectPointer();
 //
 // Wrong!
 // Because this CVector3 will not be alive in next tick
 // - my pointer will point to nothing.
 //
 _msg.pArgument2 = static_cast<CVector3*>(&vNewPosition)

 //
 // Something like that would be great
 // And would allow me to use CVector2,CVector3,CVector4 with one template member
 // 
 _msg.tSomeTemplateMember = vNewPosition;
 }

我认为您使问题复杂化。您现在有两个问题,而不是一个问题,而是如何通过两个问题,也有两个问题,如何应对模板。

实现这种事情的通常方法是使用继承: -

class Message
{
public:
  int Type () { return type; }
protected:
  int type;
};
class ClickMessage : public Message
{
public:
  ClickMessage () { type = ClickMessageID; }
private:
  // the message data
};
void HandleMessage (Message *message)
{
  switch (message->Type ())
  {
  case ClickMessageID:
    HandleClick (reinterpret_cast <ClickMessage *> (message));
    break;
  default:
    // unhandled message error
    break;
  }
}
void HandleClick (ClickMessage *message)
{
  // do stuff
}

问题是您最终重复了很多代码,即Switch语句中的铸件。还有一个维护问题 - 添加的新消息需要一些仔细的更新。您可以稍微破解代码并使用功能指针和地图将消息类型转换为函数并替换Switch语句。

可能有一个聪明的模板解决方案,但我想不到。

使用rtti可能会有所帮助(付费)。

这是一个反射确实擅长解决的问题!

也许我缺少某些东西,但是我想知道为什么您不从抽象类开始,然后从中衍生出各种事件消息。通过利用抽象类并从中得出类,可以让编译器找出您使用的Switch语句的逻辑。请参阅此C 多态性和抽象基类教程。

也从抽象类上的MSDN参见此。

例如,您可能有一个抽象类,如以下内容。但是,您可能不需要太多,实际上可能只需要单个processEvent()方法。任何派生的类都需要提供自己的版本的摘要类中指定的每个功能。

class EventMessage abstract {
public:
    virtual void *getArgument1 (void) = 0;
    virtual void *getArgument2 (void) = 0;
    virtual int   processEvent (void) = 0;
protected:
    void *pArgument1;
    void *pArgument2;
};

该抽象类定义的是一个类,基本上包含所有各种事件消息使用的数据以及一种被称为处理实际消息的方法。该类本身并未实例化,但是它被用作其他派生类的父级或超级类。

您将要做的就是派生将实现事件接口的新类。例如,这里有两个不同的类:

class JoJoEvent : public EventMessage {
public:
    JoJoEvent(void *arg1, void *arg2);
    void *getArgument1 (void);
    void *getArgument2 (void);
    int   processEvent (void);
};
JoJoEvent::JoJoEvent(void *arg1, void *arg2)
{
    pArgument1 = arg1;
    pArgument2 = arg2;
}
void * JoJoEvent::getArgument1 (void) {
    return pArgument1;
}
void * JoJoEvent::getArgument2 (void) {
    return pArgument2;
}
int JoJoEvent::processEvent (void) {
    // do stuff with the arguments
    return 1;
}
class KoKoEvent : public EventMessage {
public:
    KoKoEvent(void *arg1, void *arg2);
    void *getArgument1 (void);
    void *getArgument2 (void);
    int   processEvent (void);
};
KoKoEvent::KoKoEvent(void *arg1, void *arg2)
{
    pArgument1 = arg1;
    pArgument2 = arg2;
}
void * KoKoEvent::getArgument1 (void) {
    return pArgument1;
}
void * KoKoEvent::getArgument2 (void) {
    return pArgument2;
}
int KoKoEvent::processEvent (void) {
    // do stuff with the arguments
    return 1;
}

然后,当使用这些时,您将执行以下代码之类的事情:

EventMessage *myMessage = new JoJoEvent(0, 0);
EventMessage *myMessage2 = new KoKoEvent(0, 0);
myMessage2->processEvent();
myMessage->processEvent();

如果您需要在派生类中添加其他数据,则可以提供将数据放入派生类中的机制。