所以我正在为我的A.I.使用这个电报/信息调度系统。来自Matt Buckland"编程游戏A.I.通过实例"书。
我有MessageDispatcher类的这个方法:
void DispatchMsg(double delay, int sender, int receiver, int msg, void *additionalInfo = nullptr);
然后使用Telegram结构:
struct Telegram
{
// Messages can be either dispatched immediately or delayed for
// a specified amount of time. If a delay is necessary, this
// field is stamped with the time the message should be dispatched.
double DispatchTime;
// Who is sending this message
int Sender;
// Who should the component give this message to
// may be set to -1 if not required
int Receiver;
// Message itself, should be one of the several enumerated types
int Msg;
// Additional information that might want to be passed along
void *ExtraInfo;
Telegram():DispatchTime(-1),
Sender(-1),
Receiver(-1),
Msg(-1)
{
// Empty
}
Telegram(double time,
int sender,
int receiver,
int msg,
void *info = nullptr):DispatchTime(time),
Sender(sender),
Receiver(receiver),
Msg(msg),
ExtraInfo(info)
{
// Empty
}
};
使用像:
这样的演员template <class T>
inline T DereferenceToType(void *p)
{
return *(T*)(p);
}
麻烦在于:
void Player::playerFeed() {
if (!Target)
return;
Courier->DispatchMsg(SEND_MSG_IMMEDIATELY, PLAYER_ID, TargetedActor, MessageType::PLAYER_FED, &ActorNode->getPosition());
}
其中ActorNode-&gt; getPosition()来自Ogre3d Ogre :: SceneNode:
virtual const Vector3 & getPosition (void) const
获取节点相对于父节点的位置。
然后我回去做:
Ogre::Vector3 attackerPos = DereferenceToType<Ogre::Vector3>(msg.ExtraInfo);
我更喜欢在这里使用const Ogre :: Vector3,这可以写一个const dereference helper函数。
无论如何,问题是: xxx | 90 |警告:来自&#39; const void *&#39;的无效转换到&#39;无效*&#39; [-fpermissive] |
我理解警告;但我不确定如何纠正这个问题。
我尝试通过为DispatchMsg编写第二种方法来修复它:
void DispatchMsg(double delay, int sender, int receiver, int msg, void *additionalInfo = nullptr);
// For const void*
void DispatchMsg(double delay, int sender, int receiver, int msg, const void *additionalInfo);
但是,在电报的创建过程中,它将警告转移到了该功能中。 所以我尝试了一些东西,比如在我的Telegram结构中创建一个名为const void * ConstExtraInfo的第二个参数,麻烦的是这似乎使Telegram结构变得混乱了。
基本上我的问题是:是否有一个干净的方式实现,或者是否必须通过在电报中有额外的成员来找出存储哪种类型的信息?
可以使用void *或const void *的模板来完成:电报还是会使电报的接收端复杂化?
如果我需要发布更多相关信息,请与我们联系。 感谢。
答案 0 :(得分:2)
你的第一个问题是additionalInfo
- 指针应该是const
- 合格
然后,您的模板也应该使用const
最后,它应该返回一个引用,而不是复制数据:
template <class T> inline const T& DereferenceToType(const void *p)
{
return *(const T*)p;
}
无论如何,为何隐藏演员?相反,在收件人中这样做:
const auto& extra = *(T*)p;
答案 1 :(得分:1)
你可以使用const_cast
或普通的C样式演员来抛弃const
。这将是最快最肮脏的方式。
现在,您真正想要实现的是转换为可以从抽象类型到具体类型来回转换的中间数据类型。一种可能的方法是使用一些称为 Variant 的东西,它是一个包含一些不透明数据的类/结构和一个标识这些数据的标记。类似于:
enum DataTag {
DATA_INT,
DATA_STRING,
DATA_VEC3,
// etcetera
};
struct Variant {
virtual DataTag GetTypeTag() const = 0;
virtual int AsInt() const = 0;
virtual string AsString() const = 0;
virtual Vec3 AsVector() const = 0;
// same goes for assigning a value. I.e: FromInt()/FromString()
};
template<class T>
struct VariantImpl : public Variant {
// add constructors as needed
VariantImpl(const T & data, DataTag tag)
{
this->data = data;
this->tag = tag;
}
// implement the proper conversions
int AsInt() const { }
string AsString() const { }
Vec3 AsVector() const { }
DataTag GetTypeTag() const { return tag; }
T data;
DataTag tag;
};
然后你可以指向Variant
结构中的Telegram
,并将ExtraInfo
设置为:
telegram->ExtraInfo = new VariantImpl<int>(42);
然后使用AsInt()
随时访问它,只要您首先检查类型标记以确保允许转换。
通过这种方式,您可以添加很多内容以满足您的需求。希望它有所帮助。