I just wrote my functions for serialization or (some) objects and for some native types and encountered a curious error:
<source>: In function 'int main()':
<source>:29:34: error: call of overloaded 'deserialize<long long int>(const char [5])' is ambiguous
29 | deserialize<long long>("1337");
| ^
<source>:15:3: note: candidate: 'T deserialize(const string&) [with T = long long int; std::string = std::__cxx11::basic_string<char>]'
15 | T deserialize(std::string const &);
| ^~~~~~~~~~~
<source>:26:11: note: candidate: 'typename std::enable_if<(((! is_specialization<T, std::vector>::value) && (! is_specialization<T, std::map>::value)) && (! is_specialization<T, std::tuple>::value)), T>::type deserialize(const string&) [with T = long long int; typename std::enable_if<(((! is_specialization<T, std::vector>::value) && (! is_specialization<T, std::map>::value)) && (! is_specialization<T, std::tuple>::value)), T>::type = long long int; std::string = std::__cxx11::basic_string<char>]'
26 | long long deserialize<long long>(std::string const & llstr) { return {}; }
| ^~~~~~~~~~~~~~~~~~~~~~
I have a prototype, an overload and a specialization like this:
#include <string>
#include <type_traits>
#include <vector>
#include <map>
#include <tuple>
template<typename Test, template<typename...> class Ref>
struct is_specialization : std::false_type {};
template<template<typename...> class Ref, typename... Args>
struct is_specialization<Ref<Args...>, Ref>: std::true_type {};
// Prototype
template <typename T>
T deserialize(std::string const &);
// Default Implementation (Overload)
template <typename T>
typename std::enable_if<!is_specialization<T, std::vector>::value &&
!is_specialization<T, std::map>::value &&
!is_specialization<T, std::tuple>::value, T>::type
deserialize(std::string const &) { return {}; }
// Specialization
template <>
long long deserialize<long long>(std::string const & llstr) { return {}; }
int main() {
deserialize<long long>("1337");
}
If I call the specialization, like in the example from the error-message, I get the error above. But why is that? Shouldn't the specialization shadow the overload? And why does the compiler point to the prototype when showing the error?
I'd like to have a prototype in my hpp-file, but this code only works if I remove the prototype. How can I have both?
The implementation of is_specialization
, 463035818-is-not-a-number. I got it from here.
As for me mentioning the prototype for the header, Remy Lebeau: I like to have two hpp and one cpp file: In the (main) hpp (for the class I want to implement, I put only the declarations, no definitions. In the "..._imp.hpp" (which is included at the end of the other hpp) I put definitions for function templates. The rest (non-template-definitions and full specifications of templated functions) I write in the cpp-file. For testing, I use an online ide, so it's all part of the same "file", but for the real project I want to split the code the way I just mentioned and I felt giving reason as to why I want a separate prototype was necessary.
Yes, for the deserialize
-functions it makes most sense to me to differ by return type and as that's not possible I thought templates were the way to go. Thank you for the suggestion, Nathan Oliver. I'll look into it and see whether tag dispatch helps!