I am currently working on serializing several data structures to JSON.
The existing data structures already provide a text-based output format that I want to use as the default when the functions that convert a specific type to JSON not yet exists.
I currently have the fallback and several specific specializations done. As the JSON-library I use is already able to consume primintives like int, float etc. without any extra work, I want these types have their own (common) specialized template function.
My current main problem is that I'm not able to get to_json(1)
to call the function for fundamentals/primitives, but if I specify the type manually (to_json<int>
) the correct function is called. Is there any way to fix this? What type does the compiler deduce in the first line?
I am limited to C++11.
The following summarizes my basic setup
#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;
}
Output:
General
For fundamentals
For R
General
Your forward declare template function will capture all types. It gives trouble when initialise with concrete type.
//// Fallback. Should catch everything not caught by the specializations
//template <typename T>
//void to_json(const T& x);
Below code should work fine:
// 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;
}