2

我有一个具有两个不同功能的模板类(OutgoingPacket):

void _prepare() {
    assert(false); // this should have been specialized and the native function never called.
}

template <typename Args, typename ... RemArgs>
void _prepare(Args&& args, RemArgs&& ... remArgs) {
    assert(false); // this should have been specialized and the native function never called.
}

然后,我在类定义之外定义了两者的一些特化:

// no args
template <> void OutgoingPacket<PacketServerAck> ::_prepare();
template <> void OutgoingPacket<PacketSup>       ::_prepare();
template <> void OutgoingPacket<PacketWelcome>   ::_prepare();
template <> void OutgoingPacket<PacketServerPing>::_prepare();

// with args
template <> template <> void OutgoingPacket<PacketGTFO>::_prepare<std::string>(std::string&& message);
template <> template <> void OutgoingPacket<PacketPlayer>::_prepare<std::shared_ptr<User>>(std::shared_ptr<User>&& user);

不带参数的函数调用prepare按预期工作,但调用带参数的重载调用基本模板;他们触发断言。

为什么会这样?


更新:我刚刚尝试修改专业化定义以包含具有相同结果的引用:

template <> template <> void OutgoingPacket<PacketGTFO>::_prepare<std::string&&>(std::string&& message);
template <> template <> void OutgoingPacket<PacketPlayer>::_prepare<std::shared_ptr<User>&&>(std::shared_ptr<User>&& user);

附带说明一下,我这样做的原因是因为我不认为基类 OutgoingPacket 应该散布所有这些不同版本的准备函数。而且我觉得子类化不合适,因为不同 OutgoingPackets 之间的差异非常小(约 4 行)。

本质上,OutgoingPacket 对象是使用任意参数创建的,然后将其转发给准备函数:

template<typename ... Args>
OutgoingPacket(Args&&... args) {
    _prepare(std::forward<Args>(args)...);
}

如果这是不好的做法,我可以得到一些关于设计的建议吗?

4

1 回答 1

3

原因很可能是您使用不是右值的参数调用函数。

请注意,主可变参数模板的函数参数绑定到右值和左值:换句话说,它们是通用引用(Scott Meyers 的非标准术语),而专用模板中的函数参数绑定到右值。

// The parameters are universal references
template <typename Args, typename ... RemArgs>
void _prepare(Args&& args, RemArgs&& ... remArgs) 

// The parameters are NOT universal references
template <> template <> 
void OutgoingPacket<PacketGTFO>::_prepare<std::string>(std::string&& message);

有关通用引用如何工作的说明,请参阅本文此演示文稿。棘手的部分是&&后缀并不总是意味着右值引用:例如,在您的主模板的情况下,它不是,但在您的专用模板的情况下它确实如此。

因此,如果您的函数的输入参数是左值(例如,具有名称的变量而不是函数调用的返回值),由于常规的重载解析规则,它们将绑定到您的主模板而不是您的专用模板。

于 2013-01-28T15:02:23.127 回答