Its simplified version of my real problem. Why in the first case template specialization doesn't work?
If I swap first two functions then it will work.
Strange, but it works with msvc 19...
#include <string>
#include <vector>
#include <iostream>
template<typename T, typename M>
void write_impl(T &result, M m) {
for (const auto &i : result) {
write_impl(i, m);
}
}
template<typename M>
void write_impl(const std::string &result, M m) {
std::cout << result;
}
template<typename T>
void write_impl_1(T &result) {
for (const auto &i : result) {
write_impl_1(i);
}
}
template<>
void write_impl_1(const std::string &result) {
std::cout << result;
}
int main() {
std::vector<std::string> a{"42", "43", "44"};
write_impl(a, 42); // compile time error
write_impl_1(a); // works fine
}
The first case isn't a case of template specialization; it's function overloading.
Doesn't works because the first function call the second one that isn't declared. Switching the order, as you can see, works because the first (now second) know the declaration (and the definition too) of the second (now first).
You can't have template partial specialization for functions in C++; only full specialization.
You really need a sort of partial specialization, you can pass through a class/struct and a function inside it. You can partially specialize the struct/class.
For example
#include <string>
#include <vector>
#include <iostream>
template <typename T, typename M>
struct foo
{
static void bar (T & result, M m)
{
for (const auto &i : result)
foo<decltype(i), M>::bar(i, m);
}
};
template <typename M>
struct foo<std::string const &, M>
{
static void bar (std::string const & result, M)
{ std::cout << result; }
};
int main()
{
std::vector<std::string> a{"42", "43", "44"};
foo<decltype(a), int>::bar(a, 42);
}
But, as you can see, isn't really handy.
Obviously, if you don't need a partial-specialization-for-function emulation, and you are comfortable with different and overloaded template function (given that are calling each other) you can declare the first, declare and define the second and define the first;
Something as
template <typename M>
void write_impl (std::string const &, M);
template<typename T, typename M>
void write_impl (T & result, M m)
{
for (const auto &i : result)
write_impl(i, m);
}
template <typename M>
void write_impl (std::string const & result, M m)
{ std::cout << result; }