Reputation: 23041
I need to write a parse
function that can parse string
to other types:
OtherType parse(const std::string &s)
Since C++ doesn't allow to overload by return value, I tried to use template and template specialization:
template <typename T>
T parse(const std::string &s);
template <>
double parse(const std::string &s) { return std::stod(s); }
This works, however, I also need to specialize this function with template <typename T, typename U> std::pair<T, U>
and template <typename ...Args> std::tuple<Args...>
. Obviously, the following won't work:
template <>
template <typename T, typename U>
std::pair<T, U> parse(const std::string &s);
I DO NOT want to modify the parse
interface as the following, and overload on this function.
template <typename T>
void parse(const std::string &s, T &t);
In order to keep the interface, I tried the following:
template <typename ...>
struct Trait {};
double parse_impl(Trait<double>, const std::string &s);
template <typename T, typename U>
std::pair<T, U> parse_impl(Trait<std::pair<T, U>>, const std::string &s);
template <typename T>
T parse(const std::string &s) {
return parse_impl(Trait<T>(), s);
}
Although this works fine, I'm wondering is there any better solution? Is there any syntactic sugar can help me to write something like: template <> template <typename T, typename U> std::pair<T, U> parse(const std::string &s);
Upvotes: 1
Views: 75
Reputation: 173044
You can use class templates, which support partial template specialization; while function templates don't. e.g.
template <typename T>
struct parser {
static T parse(const std::string &s);
};
template <>
struct parser<double> {
static double parse(const std::string &s) {
return std::stod(s);
}
};
template <typename T, typename U>
struct parser<std::pair<T, U>> {
static std::pair<T, U> parse(const std::string &s) {
return ...;
}
};
template <typename... Args>
struct parser<std::tuple<Args...>> {
static std::tuple<Args...> parse(const std::string &s) {
return ...;
}
};
And add a helper function template,
template <typename... T>
inline auto parse(const std::string& s) {
return parser<T...>::parse(s);
}
And use them as,
parse<double>("");
parse<std::pair<int, int>>("");
parse<std::tuple<int, int, int>>("");
Upvotes: 1
Reputation: 13040
You can overload function templates even if their parameters are the same, so just use
// overloading, not specialization
template <typename T, typename U>
std::pair<T, U> parse(const std::string &s);
Upvotes: 0