1
votes

I'm reading C++ Templates: The Complete Guide, and in "13.7 Partial Specialization of Function Templates" author said:

To overload function templates, their function parameters must differ in some material way. Consider a function template R convert(T const&) where R and T are template parameters. We may very well want to specialize this template for R = void, but this cannot be done using overloading.

It could be done using function template overloading, right? Such as:

#include <iostream>

template <typename T, typename R>
R convert(T const&) { std:: cout << "R convert(T const&)\n"; }
template <typename T>
void convert(T const&) { std:: cout << "void convert(T const&)\n"; }

int main()
{
    convert(0);
}

DEMO here, result is:

void convert(T const&)

What does author really mean?

1
The author is probably referring to C++'s lack of support for overloading on return type. - user3553031
@nix But it's supported by function template overloading. - songyuanyao
I think that you're running into some UB that your compiler isn't smart enough to warn about. Try adding a return statement to the first convert (so that it will compile), then replace the call to convert(0)` with int i=convert(0). It won't compile. - user3553031
The compiler can't deduce R for the first template, so it's never selected. - T.C.
@nix Because author is talking about the difference between "partial specialization" and "overloading", but I think this cannot be done by specialization too. So I can't get the point of the above context from the book. - songyuanyao

1 Answers

3
votes

Consider a class template partial specialization:

template<class U, class V> class T { };

template<class V> class T<void, V> { };

When you write T<void, int>, the partial specialization will be used.

Now consider a function template:

template <typename R, typename T>
R convert(T const&) { return /* something */; } 

Note that the order of R and T are swapped in the template parameter list above. This is probably how such a template would be written - you write convert<R>(something), explicitly specifying the destination type while letting the source type be deduced by the compiler.

Now suppose you want convert<void>(something) to do something different. You can't do it with an overload:

template <typename T>
void convert(T const&) { } 

If you write convert(something) - which would previously be ill-formed, it will go to your new overload, because the compiler can't deduce R for the first template. But if you write convert<void>(something) or even convert<void, T>(something), it would still go to the original template. To make it worse, something like convert<int>(1) is now ill-formed because it's ambiguous.

In other words, you can't make convert<void, T>(something) use a different implementation than convert<int, T>(something), whereas you can do this with class template partial specializations.