for_stack
for_stack

Reputation: 23041

Specialize a template function with template class

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

Answers (2)

songyuanyao
songyuanyao

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>>("");

LIVE

Upvotes: 1

xskxzr
xskxzr

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

Related Questions