我有以下模板函数:
template <class T>
inline T ParseValueFromJson(const JSONValue& jsonValue);
这反过来又用于其他模板函数,例如:
template <class T>
bool TryGetValueFromJson(
const JSONValue& jsonValue,
const String& name,
T& variable)
{
if (!jsonValue.Contains(name))
{
return false;
}
variable = ParseValueFromJson<T>(jsonValue[name]);
return true;
}
现在我想将 ParseValueFromJson 专门用于许多不同的类型,其中之一是模板类 (Vector)。但是,使用典型的专用化意味着 Vector 的类型参数将未定义:
template <>
inline Vector<T> ParseValueFromJson<Vector<T>>(const JSONValue& jsonValue)
除此之外,在函数实现中,我需要 T 的类型,因为我将使用 ParseValueFromJson 的 T 类型版本来解析单个项目。
当然,如果我在专业化中使用模板 T,它是一个不同的函数,会导致不明确的调用:
template <typename T>
inline Vector<T> ParseValueFromJson<Vector<T>>(const JSONValue& jsonValue)
那么这是可能的,还是我需要满足于一个单独的 TryGetContainerFromJson(或类似)函数,该函数将模板化集合类型作为第二个模板参数?
我会选择处理序列化的serializer
模板结构的实现(并且可以很容易地部分专业化),因为模板函数专用化可能很麻烦。
// Default serializer implementation.
namespace impl
{
template <typename T>
struct serializer
{
T from_json(const JSONValue& jv)
{
// default implementation...
}
};
}
// Convenient interface function.
template <class T>
inline T ParseValueFromJson(const JSONValue& jsonValue)
{
return impl::serializer<T>{}.from_json(jsonValue);
}
// "Special" serializer implementations.
namespace impl
{
template <typename T>
struct serializer<Vector<T>>
{
Vector<T> from_json(const JSONValue& jv)
{
Vector<T> result;
for(auto c : jv.children())
{
result.add(ParseValueFromJson<T>(c));
}
return result;
}
};
}
<</div>
div class="one_answers"> 您不能部分专用化函数模板(指向 Herb Sutter 的强制性链接),但您始终可以重载函数模板。只需沿着主节点前进,将类型作为标记参数传递:
template <class > struct tag { };
template <class T>
inline T ParseValueFromJson(const JSONValue& jsonValue) {
return impl::ParseValueFromJson(jsonValue, tag<T>{});
}
然后提供一堆重载:
namespace impl {
template <class T>
inline T ParseValueFromJson(const JSONValue& jsonValue, tag<T> ) {
// generic, if that makes sense
}
template <class T>
inline T ParseValueFromJson(const JSONValue& jsonValue, tag<std::vector<T>> ) {
// vector version
}
// etc.
}
您不能部分专用化函数,但是您当然可以重载它,包括使用另一个模板化函数。这有效:
template <typename T>
void func(const T& arg)
{
std::cout << "General" << std::endl;
}
template <typename T>
void func(const std::vector<T>& vec)
{
std::cout << "Vector overload" << std::endl;
}
int main()
{
func(1); //outputs "General"
func(std::vector<int>{1}); //outputs "Vector overload"
return 0;
}
在您的情况下,如果您愿意按输出参数返回,您可以调整此解决方案,因此您有 2 个这样的函数:
template <class T>
inline void ParseValueFromJson(const JSONValue& jsonValue, T& output);
template <class T>
inline void ParseValueFromJson(const JSONValue& jsonValue, std::vector<T>& output);
这实际上适用于您的代码,因为您最终已经通过输出参数返回答案。因此,在您的呼叫站点,您只需更改线路即可
variable = ParseValueFromJson<T>(jsonValue[name]);
自
ParseValueFromJson<T>(jsonValue[name], variable);