10

如何专门化采用通用引用参数的函数模板?

foo.hpp:

template<typename T>
void foo(T && t)    // universal reference parameter

foo.cpp

template<>
void foo<Class>(Class && class) {
    // do something complicated
}

在这里,Class不再是推导类型,因此是Class精确的;不可能Class &,所以参考折叠规则在这里对我没有帮助。我也许可以创建另一个接受Class &参数的专业化(我不确定),但这意味着foo为所有参数的每个可能的右值/左值引用组合复制其中包含的所有代码,这是通用引用应该避免的.

有没有办法做到这一点?

如果有更好的解决方法,请更具体地说明我的问题:

我有一个可以连接到多个游戏服务器的程序,并且每个服务器在大多数情况下都以相同的名称调用所有内容。但是,它们在某些方面的版本略有不同。这些东西可以有几个不同的类别:移动、项目等。我编写了一个通用的“移动字符串移动枚举”函数集供内部代码调用,我的服务器接口代码也有类似的职能。但是,有些服务器有自己的内部 ID 可以与之通信,有些使用字符串,有些则在不同的情况下使用两者。

现在我想做的是让它更通用一点。

我希望能够调用类似ServerNamespace::server_cast<Destination>(source). 这将允许我从 aMove转换为 a std::stringor ServerMoveID。在内部,我可能需要制作副本(或从中移出),因为某些服务器要求我保留已发送消息的历史记录。通用引用似乎是解决这个问题的明显方法。

我现在正在考虑的头文件将简单地公开以下内容:

namespace ServerNamespace {

template<typename Destination, typename Source>
Destination server_cast(Source && source);

}

并且实现文件将所有合法转换定义为模板特化。

4

2 回答 2

2

我认为最好的解决方案是使用标签调度系统,在该系统中重载标签而不是实际类型:

struct foo {
    struct tag {};
};

struct bar {
    struct tag {};
};

template<typename Destination, typename Source>
Destination server_cast(Source && source, foo::tag) {
    // foo
}

template<typename Destination, typename Source>
Destination server_cast(Source && source, bar::tag) {
    // bar
}

template<typename Destination, typename Source>
Destination server_cast(Source && source) {
    return server_cast<Destination>(std::forward<Source>(source), typename std::remove_reference<Source>::type::tag());
}
于 2012-11-30T22:48:26.060 回答
1

最可扩展的事情是创建一个模板类专业化。

template< class X > struct Whatever {
    void f(){ ... }
};

template<> struct Whatever<UserType> {
    void f(){ ... }
};

我说这是最可扩展的原因是因为你可以在任何地方添加一个特化,无论是在定义什么的文件内部或外部。

这是对 Pubby 建议的标签调度解决方案的补充,而不是排他性。

于 2012-11-30T23:02:21.983 回答