结构中的C ++模板类型

时间:2012-11-01 21:23:10

标签: c++ templates struct

这是我的MESSAGE结构:

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;

 }

2 个答案:

答案 0 :(得分:2)

我认为你的问题太复杂了。而不是一个问题,如何在消息中传递任意数据,你现在有两个,如何处理模板。

实现此类事情的常用方法是使用继承: -

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可能有所帮助(需要付费)。

这是反思真正善于解决的一个问题!

答案 1 :(得分:1)

也许我错过了一些东西但是我想知道你为什么不从一个抽象类开始,然后从中派生你的各种事件消息。通过利用抽象类并从中派生类,您可以让编译器找出使用switch语句的逻辑。请参阅此C++ Polymorphism and Abstract Base Class tutorial

另见MSDN on Abstract classes

例如,您可能有一个类似于以下内容的抽象类。但是,您可能不需要这么多,实际上可能只需要单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;
};

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

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

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();

如果需要在派生类中添加其他数据,可以这样做,只需提供一种机制将数据放入派生类中。