【问题标题】:Overload resolution and template functions重载解析和模板函数
【发布时间】:2013-01-28 14:52:22
【问题描述】:

我有一个具有两个不同功能的模板类(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);

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

为什么会这样?


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

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 应该散布所有这些不同版本的 prepare 函数。而且我觉得子类化不合适,因为不同 OutgoingPackets 之间的差异非常小(约 4 行)。

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

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

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

【问题讨论】:

    标签: c++ templates overloading specialization


    【解决方案1】:

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

    请注意,主可变参数模板的函数参数同时绑定到右值和左值:换句话说,它们是通用引用(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);
    

    请参阅this articlethis presentation,了解通用引用的工作原理。棘手的部分是&amp;&amp; 后缀并不总是意味着右值引用:例如,在您的主模板的情况下,它不是,但在您的专用模板的情况下却是这样。

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

    【讨论】:

    • 我似乎没有使用右值。我在尝试时收到编译时错误,我想还有更多问题需要解决。
    猜你喜欢
    • 1970-01-01
    • 2016-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多