The following code compiles fine, but produces a linker error:
class Base {};
class Derived : public Base {};
template
void f(const T&am
Assuming you really need to have the template and must have all derivatives of Base
to call the specialization, you could replace the specialization with an overload and disable the template for all types that derive from Base
using type traits:
template <typename T, typename std::enable_if<!std::is_base_of<Base, T>::value>::type>
void f(const T& value);
// no template
void f(const Base& value)
That way only the overload for Base
is available to the derived types.
The problem is here:
template <typename T>
void f(const T& value);
This function is not defined, however it is the best match for the compiler when you invoke
f(d)
with Derived d;
The Base
specialization template<> void f(const Base& value)
participates in the overload resolution for f(d)
, however it is less suitable than the full template template <typename T> void f(const T& value)
.
One idea is to remove the specialization altogether, define only the full template, and the code will probably do what you want.
Like the others have said, you haven't defined the generic template function, which is the best candidate for the derived type. If you want to better understand how template function overload resolution works, consult this reference here: http://en.cppreference.com/w/cpp/language/function_template#Function_template_overloading
Your example is a bit contrived (perhaps for brevity's sake). But in general, you should only provide template specializations if you need to implement special logic for a particular type, or if you want to define your template class(es) and function(s) in a separate source file and only need/want to support certain types. Maybe this is what you're actually going for, but generics are called generics for a reason.
The linker error occurs because you haven't defined, only declared, the function template
template <typename T>
void f(const T& value);
To avoid it, define the above template and your code will compile, but presumably it still doesn't do what you want.
When calling f
with an argument of type Derived
the above template is a better match compared to your specialization because the latter requires a derived-to-base conversion while the former doesn't.
You can achieve the behavior you want by using enable_if to allow the first template to participate in overload resolution only if the deduced template argument type is not Base
or a type derived from Base
.
template <typename T>
typename std::enable_if<!std::is_base_of<Base, T>::value>::type
f(const T& value) {
}
And change the other f
so it's not a specialization, but just an overload.
void f(const Base& value) {
// ...
}
Live demo
In general, prefer overloading function templates over specialization. Read this to learn about the pitfalls of function template specialization.