我目前正在致力于将多个数据结构序列化为 JSON。
现有的数据结构已经提供了基于文本的输出格式,当将特定类型转换为 JSON 的函数尚不存在时,我想将其用作默认格式。
我目前已经完成了后备和几个特定的专业化。由于我使用的 JSON 库已经能够使用 int、float 等基元,无需任何额外的工作,我希望这些类型有自己的(通用)专用模板函数。
我当前的主要问题是我无法让
to_json(1)
调用基础/基元的函数,但如果我手动指定类型(to_json<int>
),则会调用正确的函数。有没有什么办法解决这一问题?编译器在第一行推导出什么类型?
我仅限于 C++11。
以下总结了我的基本设置
#include <iostream>
#include <type_traits>
// Should rely on fallback
struct S {
};
// Has specialization
struct R {
};
// Fallback. Should catch everything not caught by the specializations
template <typename T>
void to_json(const T& x);
// Specialization for R
template<>
void to_json(const R& x)
{
std::cout << "For R\n";
}
// Does not work
// Specialization for all fundamentals (e.g. int)
template<typename T>
void to_json(const typename std::enable_if<std::is_fundamental<T>::value, T>::type& x)
{
std::cout << "For fundamentals\n";
}
template <typename T>
void to_json(const T& x)
{
std::cout << "General\n";
}
int main()
{
to_json(1); // General. (WRONG, expected fundamentals)
to_json<int>(1); // fundamentals (CORRECT)
to_json(R{}); // R (CORRECT)
to_json(S{}); // General (CORRECT)
return 0;
}
输出:
General
For fundamentals
For R
General
您的前向声明模板函数将捕获所有类型。使用具体类型初始化时会遇到麻烦。
//// Fallback. Should catch everything not caught by the specializations
//template <typename T>
//void to_json(const T& x);
下面的代码应该可以正常工作:
// Should rely on fallback
struct S {
};
// Has specialization
struct R {
};
// note: also use enable_if_t to exclude fundamental type
// otherwise compiler is still confused by the redefinition
template <typename T,
std::enable_if_t<!std::is_fundamental<T>::value, bool> = true>
void to_json(const T& x)
{
std::cout << "General\n";
}
// Specialization for R
template<>
void to_json(const R& x)
{
std::cout << "For R\n";
}
// Specialization for all fundamentals (e.g. int)
template<typename T,
std::enable_if_t<std::is_fundamental<T>::value, bool> = true>
void to_json(const T& x)
{
std::cout << "For fundamentals\n";
}
int main()
{
to_json(1); // General. (WRONG, expected fundamentals)
to_json<int>(1); // fundamentals (CORRECT)
to_json(R{}); // R (CORRECT)
to_json(S{}); // General (CORRECT)
return 0;
}